diff mbox series

[v2,5/6] drm/vs: Add KMS crtc&plane

Message ID 20231025103957.3776-6-keith.zhao@starfivetech.com
State New
Headers show
Series None | expand

Commit Message

Keith Zhao Oct. 25, 2023, 10:39 a.m. UTC
add 2 crtcs and 8 planes in vs-drm

Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile   |    8 +-
 drivers/gpu/drm/verisilicon/vs_crtc.c  |  257 ++++
 drivers/gpu/drm/verisilicon/vs_crtc.h  |   43 +
 drivers/gpu/drm/verisilicon/vs_dc.c    | 1002 ++++++++++++
 drivers/gpu/drm/verisilicon/vs_dc.h    |   80 +
 drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1959 ++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_dc_hw.h |  492 ++++++
 drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
 drivers/gpu/drm/verisilicon/vs_plane.c |  526 +++++++
 drivers/gpu/drm/verisilicon/vs_plane.h |   58 +
 drivers/gpu/drm/verisilicon/vs_type.h  |   69 +
 11 files changed, 4494 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
 create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
 create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h

Comments

Keith Zhao Nov. 14, 2023, 10:42 a.m. UTC | #1
On 2023/10/26 3:28, Dmitry Baryshkov wrote:
> On 25/10/2023 13:39, Keith Zhao wrote:
>> add 2 crtcs and 8 planes in vs-drm
>> 
>> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> ---
>>   drivers/gpu/drm/verisilicon/Makefile   |    8 +-
>>   drivers/gpu/drm/verisilicon/vs_crtc.c  |  257 ++++
>>   drivers/gpu/drm/verisilicon/vs_crtc.h  |   43 +
>>   drivers/gpu/drm/verisilicon/vs_dc.c    | 1002 ++++++++++++
>>   drivers/gpu/drm/verisilicon/vs_dc.h    |   80 +
>>   drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1959 ++++++++++++++++++++++++
>>   drivers/gpu/drm/verisilicon/vs_dc_hw.h |  492 ++++++
>>   drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
>>   drivers/gpu/drm/verisilicon/vs_plane.c |  526 +++++++
>>   drivers/gpu/drm/verisilicon/vs_plane.h |   58 +
>>   drivers/gpu/drm/verisilicon/vs_type.h  |   69 +
>>   11 files changed, 4494 insertions(+), 2 deletions(-)
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
>>   create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
>> 
>> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
>> index 7d3be305b..1d48016ca 100644
>> --- a/drivers/gpu/drm/verisilicon/Makefile
>> +++ b/drivers/gpu/drm/verisilicon/Makefile
>> @@ -1,7 +1,11 @@
>>   # SPDX-License-Identifier: GPL-2.0
>>   
>> -vs_drm-objs := vs_drv.o \
>> -		vs_modeset.o
>> +vs_drm-objs := vs_dc_hw.o \
>> +		vs_dc.o \
>> +		vs_crtc.o \
>> +		vs_drv.o \
>> +		vs_modeset.o \
>> +		vs_plane.o
>>   
>>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>>   
>> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
>> new file mode 100644
>> index 000000000..8a658ea77
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
>> @@ -0,0 +1,257 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + *
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/media-bus-format.h>
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_gem_atomic_helper.h>
>> +#include <drm/drm_vblank.h>
>> +#include <drm/vs_drm.h>
>> +
>> +#include "vs_crtc.h"
>> +#include "vs_dc.h"
>> +#include "vs_drv.h"
>> +
>> +static void vs_crtc_reset(struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc_state *state;
>> +
>> +	if (crtc->state) {
>> +		__drm_atomic_helper_crtc_destroy_state(crtc->state);
>> +
>> +		state = to_vs_crtc_state(crtc->state);
>> +		kfree(state);
>> +		crtc->state = NULL;
>> +	}
> 
> You can call your crtc_destroy_state function directly here.
> 
>> +
>> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +	if (!state)
>> +		return;
>> +
>> +	__drm_atomic_helper_crtc_reset(crtc, &state->base);
>> +}
>> +
>> +static struct drm_crtc_state *
>> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc_state *ori_state;
> 
> It might be a matter of taste, but it is usually old_state.
> 
>> +	struct vs_crtc_state *state;
>> +
>> +	if (!crtc->state)
>> +		return NULL;
>> +
>> +	ori_state = to_vs_crtc_state(crtc->state);
>> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +	if (!state)
>> +		return NULL;
>> +
>> +	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
>> +
>> +	state->output_fmt = ori_state->output_fmt;
>> +	state->encoder_type = ori_state->encoder_type;
>> +	state->bpp = ori_state->bpp;
>> +	state->underflow = ori_state->underflow;
> 
> Can you use kmemdup instead?
> 
>> +
>> +	return &state->base;
>> +}
>> +
>> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
>> +					 struct drm_crtc_state *state)
>> +{
>> +	__drm_atomic_helper_crtc_destroy_state(state);
>> +	kfree(to_vs_crtc_state(state));
>> +}
>> +
>> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	vs_dc_enable_vblank(dc, true);
>> +
>> +	return 0;
>> +}
>> +
>> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	vs_dc_enable_vblank(dc, false);
>> +}
>> +
>> +static const struct drm_crtc_funcs vs_crtc_funcs = {
>> +	.set_config		= drm_atomic_helper_set_config,
>> +	.page_flip		= drm_atomic_helper_page_flip,
> 
> destroy is required, see drm_mode_config_cleanup()

hi Dmitry:
if define destroy in drm_crtc_funcs,
it will make __drmm_crtc_init_with_planes unhappy

see:
__printf(6, 0)
static int __drmm_crtc_init_with_planes(struct drm_device *dev,
					struct drm_crtc *crtc,
					struct drm_plane *primary,
					struct drm_plane *cursor,
					const struct drm_crtc_funcs *funcs,
					const char *name,
					va_list args)
{
	int ret;

	drm_WARN_ON(dev, funcs && funcs->destroy);

........
}

It should not need to be defined here, I think

> 
>> +	.reset			= vs_crtc_reset,
>> +	.atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
>> +	.atomic_destroy_state	= vs_crtc_atomic_destroy_state,
> 
> please consider adding atomic_print_state to output driver-specific bits.
> 
>> +	.enable_vblank		= vs_crtc_enable_vblank,
>> +	.disable_vblank		= vs_crtc_disable_vblank,
>> +};
>> +
>> +static u8 cal_pixel_bits(u32 bus_format)
> 
> This looks like a generic helper code, which can go to a common place.
> 
>> +{
>> +	u8 bpp;
>> +
>> +	switch (bus_format) {
>> +	case MEDIA_BUS_FMT_RGB565_1X16:
>> +	case MEDIA_BUS_FMT_UYVY8_1X16:
>> +		bpp = 16;
>> +		break;
>> +	case MEDIA_BUS_FMT_RGB666_1X18:
>> +	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
>> +		bpp = 18;
>> +		break;
>> +	case MEDIA_BUS_FMT_UYVY10_1X20:
>> +		bpp = 20;
>> +		break;
>> +	case MEDIA_BUS_FMT_BGR888_1X24:
>> +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
>> +	case MEDIA_BUS_FMT_YUV8_1X24:
>> +		bpp = 24;
>> +		break;
>> +	case MEDIA_BUS_FMT_RGB101010_1X30:
>> +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
>> +	case MEDIA_BUS_FMT_YUV10_1X30:
>> +		bpp = 30;
>> +		break;
>> +	default:
>> +		bpp = 24;
>> +		break;
>> +	}
>> +
>> +	return bpp;
>> +}
>> +
>> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
>> +				  struct drm_atomic_state *state)
>> +{
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
>> +
>> +	vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
>> +
>> +	vs_dc_enable(dc, crtc);
>> +	drm_crtc_vblank_on(crtc);
>> +}
>> +
>> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
>> +				   struct drm_atomic_state *state)
>> +{
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	drm_crtc_vblank_off(crtc);
>> +
>> +	vs_dc_disable(dc, crtc);
>> +
>> +	if (crtc->state->event && !crtc->state->active) {
>> +		spin_lock_irq(&crtc->dev->event_lock);
>> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> +		spin_unlock_irq(&crtc->dev->event_lock);
>> +
>> +		crtc->state->event = NULL;
> 
> I think even should be cleared within the lock.
> 
>> +	}
>> +}
>> +
>> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
>> +				 struct drm_atomic_state *state)
>> +{
>> +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
>> +									  crtc);
>> +
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct device *dev = vs_crtc->dev;
>> +	struct drm_property_blob *blob = crtc->state->gamma_lut;
>> +	struct drm_color_lut *lut;
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +
>> +	if (crtc_state->color_mgmt_changed) {
>> +		if (blob && blob->length) {
>> +			lut = blob->data;
>> +			vs_dc_set_gamma(dc, crtc, lut,
>> +					blob->length / sizeof(*lut));
>> +			vs_dc_enable_gamma(dc, crtc, true);
>> +		} else {
>> +			vs_dc_enable_gamma(dc, crtc, false);
>> +		}
>> +	}
>> +}
>> +
>> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
>> +				 struct drm_atomic_state *state)
>> +{
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct drm_pending_vblank_event *event = crtc->state->event;
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	vs_dc_commit(dc);
>> +
>> +	if (event) {
>> +		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
>> +
>> +		spin_lock_irq(&crtc->dev->event_lock);
>> +		drm_crtc_arm_vblank_event(crtc, event);
>> +		spin_unlock_irq(&crtc->dev->event_lock);
>> +		crtc->state->event = NULL;
> 
> I think even should be cleared within the lock.
> 
>> +	}
>> +}
>> +
>> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
>> +	.atomic_check = drm_crtc_helper_atomic_check,
>> +	.atomic_enable	= vs_crtc_atomic_enable,
>> +	.atomic_disable = vs_crtc_atomic_disable,
>> +	.atomic_begin	= vs_crtc_atomic_begin,
>> +	.atomic_flush	= vs_crtc_atomic_flush,
>> +};
>> +
>> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
>> +	{ VS_SINGLE_DC,				"single dc mode" },
>> +	{ VS_MULTI_DC_PRIMARY,		"primary dc for multi dc mode" },
>> +	{ VS_MULTI_DC_SECONDARY,	"secondary dc for multi dc mode" },
>> +};
>> +
>> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
>> +			       struct vs_dc_info *info)
>> +{
>> +	struct vs_crtc *crtc;
>> +	int ret;
>> +
>> +	if (!info)
>> +		return NULL;
>> +
>> +	crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL);
>> +	if (!crtc)
>> +		return NULL;
>> +
>> +	ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base,
>> +					 NULL, NULL, &vs_crtc_funcs,
>> +					 info->name ? info->name : NULL);
> 
> It might be better to add drmm_crtc_init() helper.
> 
>> +	if (ret)
>> +		return NULL;
>> +
>> +	drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
>> +
>> +	if (info->gamma_size) {
>> +		ret = drm_mode_crtc_set_gamma_size(&crtc->base,
>> +						   info->gamma_size);
>> +		if (ret)
>> +			return NULL;
>> +
>> +		drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
>> +					   info->gamma_size);
>> +	}
>> +
>> +	crtc->max_bpc = info->max_bpc;
>> +	crtc->color_formats = info->color_formats;
>> +	return crtc;
>> +}
>> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
>> new file mode 100644
>> index 000000000..526dd63e5
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
>> @@ -0,0 +1,43 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_CRTC_H__
>> +#define __VS_CRTC_H__
>> +
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +
>> +#include "vs_type.h"
>> +
>> +struct vs_crtc_state {
>> +	struct drm_crtc_state base;
>> +
>> +	u32 output_fmt;
>> +	u8 encoder_type;
>> +	u8 bpp;
>> +	bool underflow;
>> +};
>> +
>> +struct vs_crtc {
>> +	struct drm_crtc base;
>> +	struct device *dev;
>> +	unsigned int max_bpc;
>> +	unsigned int color_formats;
>> +};
>> +
>> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
>> +			       struct vs_dc_info *info);
>> +
>> +static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
>> +{
>> +	return container_of(crtc, struct vs_crtc, base);
>> +}
>> +
>> +static inline struct vs_crtc_state *
>> +to_vs_crtc_state(struct drm_crtc_state *state)
>> +{
>> +	return container_of(state, struct vs_crtc_state, base);
>> +}
>> +#endif /* __VS_CRTC_H__ */
>> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
>> new file mode 100644
>> index 000000000..b5ab92d98
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_dc.c
>> @@ -0,0 +1,1002 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#include <linux/component.h>
>> +#include <linux/clk.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/reset.h>
>> +
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_blend.h>
>> +#include <drm/drm_framebuffer.h>
>> +#include <drm/drm_vblank.h>
>> +#include <drm/vs_drm.h>
>> +
>> +#include "vs_dc_hw.h"
>> +#include "vs_dc.h"
>> +#include "vs_drv.h"
>> +
>> +static const char * const vout_clocks[] = {
>> +	"noc_bus",
>> +	"channel0",
>> +	"channel1",
>> +	"dc_core",
>> +	"axi_core",
>> +	"ahb",
>> +	"hdmi_tx",
>> +	"dc_parent",
>> +
>> +};
>> +
>> +static const char * const vout_resets[] = {
>> +	"axi",
>> +	"ahb",
>> +	"core",
>> +};
>> +
>> +static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
>> +{
>> +	u8 f = FORMAT_A8R8G8B8;
>> +
>> +	switch (format) {
>> +	case DRM_FORMAT_XRGB4444:
>> +	case DRM_FORMAT_RGBX4444:
>> +	case DRM_FORMAT_XBGR4444:
>> +	case DRM_FORMAT_BGRX4444:
>> +		f = FORMAT_X4R4G4B4;
>> +		break;
>> +	case DRM_FORMAT_ARGB4444:
>> +	case DRM_FORMAT_RGBA4444:
>> +	case DRM_FORMAT_ABGR4444:
>> +	case DRM_FORMAT_BGRA4444:
>> +		f = FORMAT_A4R4G4B4;
>> +		break;
>> +	case DRM_FORMAT_XRGB1555:
>> +	case DRM_FORMAT_RGBX5551:
>> +	case DRM_FORMAT_XBGR1555:
>> +	case DRM_FORMAT_BGRX5551:
>> +		f = FORMAT_X1R5G5B5;
>> +		break;
>> +	case DRM_FORMAT_ARGB1555:
>> +	case DRM_FORMAT_RGBA5551:
>> +	case DRM_FORMAT_ABGR1555:
>> +	case DRM_FORMAT_BGRA5551:
>> +		f = FORMAT_A1R5G5B5;
>> +		break;
>> +	case DRM_FORMAT_RGB565:
>> +	case DRM_FORMAT_BGR565:
>> +		f = FORMAT_R5G6B5;
>> +		break;
>> +	case DRM_FORMAT_XRGB8888:
>> +	case DRM_FORMAT_RGBX8888:
>> +	case DRM_FORMAT_XBGR8888:
>> +	case DRM_FORMAT_BGRX8888:
>> +		f = FORMAT_X8R8G8B8;
>> +		break;
>> +	case DRM_FORMAT_ARGB8888:
>> +	case DRM_FORMAT_RGBA8888:
>> +	case DRM_FORMAT_ABGR8888:
>> +	case DRM_FORMAT_BGRA8888:
>> +		f = FORMAT_A8R8G8B8;
>> +		break;
>> +	case DRM_FORMAT_YUYV:
>> +	case DRM_FORMAT_YVYU:
>> +		f = FORMAT_YUY2;
>> +		break;
>> +	case DRM_FORMAT_UYVY:
>> +	case DRM_FORMAT_VYUY:
>> +		f = FORMAT_UYVY;
>> +		break;
>> +	case DRM_FORMAT_YUV420:
>> +	case DRM_FORMAT_YVU420:
>> +		f = FORMAT_YV12;
>> +		break;
>> +	case DRM_FORMAT_NV21:
>> +		f = FORMAT_NV12;
>> +		break;
>> +	case DRM_FORMAT_NV16:
>> +	case DRM_FORMAT_NV61:
>> +		f = FORMAT_NV16;
>> +		break;
>> +	case DRM_FORMAT_P010:
>> +		f = FORMAT_P010;
>> +		break;
>> +	case DRM_FORMAT_ARGB2101010:
>> +	case DRM_FORMAT_RGBA1010102:
>> +	case DRM_FORMAT_ABGR2101010:
>> +	case DRM_FORMAT_BGRA1010102:
>> +		f = FORMAT_A2R10G10B10;
>> +		break;
>> +	case DRM_FORMAT_NV12:
>> +		f = FORMAT_NV12;
>> +		break;
>> +	case DRM_FORMAT_YUV444:
>> +		f = FORMAT_YUV444;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	fb->format = f;
>> +}
>> +
>> +static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
>> +{
>> +	fb->swizzle = SWIZZLE_ARGB;
>> +	fb->uv_swizzle = 0;
>> +
>> +	switch (format) {
>> +	case DRM_FORMAT_RGBX4444:
>> +	case DRM_FORMAT_RGBA4444:
>> +	case DRM_FORMAT_RGBX5551:
>> +	case DRM_FORMAT_RGBA5551:
>> +	case DRM_FORMAT_RGBX8888:
>> +	case DRM_FORMAT_RGBA8888:
>> +	case DRM_FORMAT_RGBA1010102:
>> +		fb->swizzle = SWIZZLE_RGBA;
>> +		break;
>> +	case DRM_FORMAT_XBGR4444:
>> +	case DRM_FORMAT_ABGR4444:
>> +	case DRM_FORMAT_XBGR1555:
>> +	case DRM_FORMAT_ABGR1555:
>> +	case DRM_FORMAT_BGR565:
>> +	case DRM_FORMAT_XBGR8888:
>> +	case DRM_FORMAT_ABGR8888:
>> +	case DRM_FORMAT_ABGR2101010:
>> +		fb->swizzle = SWIZZLE_ABGR;
>> +		break;
>> +	case DRM_FORMAT_BGRX4444:
>> +	case DRM_FORMAT_BGRA4444:
>> +	case DRM_FORMAT_BGRX5551:
>> +	case DRM_FORMAT_BGRA5551:
>> +	case DRM_FORMAT_BGRX8888:
>> +	case DRM_FORMAT_BGRA8888:
>> +	case DRM_FORMAT_BGRA1010102:
>> +		fb->swizzle = SWIZZLE_BGRA;
>> +		break;
>> +	case DRM_FORMAT_YVYU:
>> +	case DRM_FORMAT_VYUY:
>> +	case DRM_FORMAT_NV21:
>> +	case DRM_FORMAT_NV61:
>> +		fb->uv_swizzle = 1;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +}
>> +
>> +static inline void update_watermark(struct drm_property_blob *watermark,
>> +				    struct dc_hw_fb *fb)
>> +{
>> +	struct drm_vs_watermark *data;
>> +
>> +	fb->water_mark = 0;
>> +
>> +	if (watermark) {
>> +		data = watermark->data;
>> +		fb->water_mark = data->watermark & 0xFFFFF;
>> +	}
>> +}
>> +
>> +static inline u8 to_vs_rotation(unsigned int rotation)
>> +{
>> +	u8 rot;
>> +
>> +	switch (rotation & DRM_MODE_REFLECT_MASK) {
>> +	case DRM_MODE_REFLECT_X:
>> +		rot = FLIP_X;
>> +		return rot;
>> +	case DRM_MODE_REFLECT_Y:
>> +		rot = FLIP_Y;
>> +		return rot;
>> +	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
>> +		rot = FLIP_XY;
>> +		return rot;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	switch (rotation & DRM_MODE_ROTATE_MASK) {
>> +	case DRM_MODE_ROTATE_0:
>> +		rot = ROT_0;
>> +		break;
>> +	case DRM_MODE_ROTATE_90:
>> +		rot = ROT_90;
>> +		break;
>> +	case DRM_MODE_ROTATE_180:
>> +		rot = ROT_180;
>> +		break;
>> +	case DRM_MODE_ROTATE_270:
>> +		rot = ROT_270;
>> +		break;
>> +	default:
>> +		rot = ROT_0;
>> +		break;
>> +	}
>> +
>> +	return rot;
>> +}
>> +
>> +static inline u8 to_vs_yuv_color_space(u32 color_space)
>> +{
>> +	u8 cs;
>> +
>> +	switch (color_space) {
>> +	case DRM_COLOR_YCBCR_BT601:
>> +		cs = COLOR_SPACE_601;
>> +		break;
>> +	case DRM_COLOR_YCBCR_BT709:
>> +		cs = COLOR_SPACE_709;
>> +		break;
>> +	case DRM_COLOR_YCBCR_BT2020:
>> +		cs = COLOR_SPACE_2020;
>> +		break;
>> +	default:
>> +		cs = COLOR_SPACE_601;
>> +		break;
>> +	}
>> +
>> +	return cs;
>> +}
>> +
>> +static inline u8 to_vs_tile_mode(u64 modifier)
>> +{
>> +	if (modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
>> +		return DC_TILE_MODE4X4;
>> +
>> +	return (u8)(modifier & DRM_FORMAT_MOD_VERISILICON_NORM_MODE_MASK);
>> +}
>> +
>> +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
>> +{
>> +	u8 panel_num = dc->hw.info->panel_num;
>> +	u32 index = drm_crtc_index(crtc);
>> +	int i;
>> +
>> +	for (i = 0; i < panel_num; i++) {
>> +		if (index == dc->crtc[i]->base.index)
>> +			return i;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
>> +					  unsigned int alignment)
>> +{
>> +	struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
>> +
>> +	if (alignment > priv->pitch_alignment)
>> +		priv->pitch_alignment = alignment;
>> +}
>> +
>> +static int plda_clk_rst_init(struct device *dev)
>> +{
>> +	int ret = 0;
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +
>> +	ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
>> +	if (ret) {
>> +		dev_err(dev, "failed to enable clocks\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
>> +	return ret;
>> +}
>> +
>> +static void plda_clk_rst_deinit(struct device *dev)
>> +{
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +
>> +	reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
>> +	clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
>> +}
>> +
>> +static void dc_deinit(struct device *dev)
>> +{
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +
>> +	dc_hw_enable_interrupt(&dc->hw, 0);
>> +	dc_hw_deinit(&dc->hw);
>> +	plda_clk_rst_deinit(dev);
>> +}
>> +
>> +static int dc_init(struct device *dev)
>> +{
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +	int ret;
>> +
>> +	dc->first_frame = true;
>> +
>> +	ret = plda_clk_rst_init(dev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "failed to init dc clk reset: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = dc_hw_init(&dc->hw);
>> +	if (ret) {
>> +		dev_err(dev, "failed to init DC HW\n");
>> +		return ret;
>> +	}
>> +	return 0;
>> +}
>> +
>> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
>> +	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
>> +	struct dc_hw_display display;
>> +
>> +	display.bus_format = crtc_state->output_fmt;
>> +	display.h_active = mode->hdisplay;
>> +	display.h_total = mode->htotal;
>> +	display.h_sync_start = mode->hsync_start;
>> +	display.h_sync_end = mode->hsync_end;
>> +	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
>> +		display.h_sync_polarity = true;
>> +	else
>> +		display.h_sync_polarity = false;
>> +
>> +	display.v_active = mode->vdisplay;
>> +	display.v_total = mode->vtotal;
>> +	display.v_sync_start = mode->vsync_start;
>> +	display.v_sync_end = mode->vsync_end;
>> +
>> +	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
>> +		display.v_sync_polarity = true;
>> +	else
>> +		display.v_sync_polarity = false;
>> +
>> +	display.id = to_vs_display_id(dc, crtc);
>> +
>> +	display.enable = true;
>> +
>> +	if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
>> +		dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
>> +		clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
>> +		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
>> +			       dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
>> +	} else {
>> +		dc_hw_set_out(&dc->hw, OUT_DP, display.id);
>> +		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
>> +			       dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
>> +	}
>> +
>> +	dc_hw_setup_display(&dc->hw, &display);
>> +}
>> +
>> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc)
>> +{
>> +	struct dc_hw_display display;
>> +
>> +	display.id = to_vs_display_id(dc, crtc);
>> +	display.enable = false;
>> +
>> +	dc_hw_setup_display(&dc->hw, &display);
>> +}
>> +
>> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
>> +		     struct drm_color_lut *lut, unsigned int size)
>> +{
>> +	u16 i, r, g, b;
>> +	u8 bits, id;
>> +
>> +	if (size != dc->hw.info->gamma_size) {
>> +		drm_err(crtc->dev, "gamma size does not match!\n");
>> +		return;
>> +	}
>> +
>> +	id = to_vs_display_id(dc, crtc);
>> +
>> +	bits = dc->hw.info->gamma_bits;
>> +	for (i = 0; i < size; i++) {
>> +		r = drm_color_lut_extract(lut[i].red, bits);
>> +		g = drm_color_lut_extract(lut[i].green, bits);
>> +		b = drm_color_lut_extract(lut[i].blue, bits);
>> +		dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
>> +	}
>> +}
>> +
>> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
>> +			bool enable)
>> +{
>> +	u8 id;
>> +
>> +	id = to_vs_display_id(dc, crtc);
>> +	dc_hw_enable_gamma(&dc->hw, id, enable);
>> +}
>> +
>> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable)
>> +{
>> +	dc_hw_enable_interrupt(&dc->hw, enable);
>> +}
>> +
>> +static u32 calc_factor(u32 src, u32 dest)
>> +{
>> +	u32 factor = 1 << 16;
>> +
>> +	if (src > 1 && dest > 1)
>> +		factor = ((src - 1) << 16) / (dest - 1);
>> +
>> +	return factor;
>> +}
>> +
>> +static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
>> +			 struct dc_hw_scale *scale)
>> +{
>> +	int dst_w = drm_rect_width(&state->dst);
>> +	int dst_h = drm_rect_height(&state->dst);
>> +	int src_w, src_h, temp;
>> +
>> +	scale->enable = false;
>> +
>> +	if (roi->enable) {
>> +		src_w = roi->width;
>> +		src_h = roi->height;
>> +	} else {
>> +		src_w = drm_rect_width(&state->src) >> 16;
>> +		src_h = drm_rect_height(&state->src) >> 16;
>> +	}
>> +
>> +	if (drm_rotation_90_or_270(state->rotation)) {
>> +		temp = src_w;
>> +		src_w = src_h;
>> +		src_h = temp;
>> +	}
>> +
>> +	if (src_w != dst_w) {
>> +		scale->scale_factor_x = calc_factor(src_w, dst_w);
>> +		scale->enable = true;
>> +	} else {
>> +		scale->scale_factor_x = 1 << 16;
>> +	}
>> +	if (src_h != dst_h) {
>> +		scale->scale_factor_y = calc_factor(src_h, dst_h);
>> +		scale->enable = true;
>> +	} else {
>> +		scale->scale_factor_y = 1 << 16;
>> +	}
>> +}
>> +
>> +static void update_fb(struct vs_plane *plane, u8 display_id,
>> +		      struct dc_hw_fb *fb, struct drm_plane_state *state)
>> +{
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> +	struct drm_framebuffer *drm_fb = state->fb;
>> +	struct drm_rect *src = &state->src;
>> +
>> +	fb->display_id = display_id;
>> +	fb->y_address = plane_state->dma_addr[0];
>> +	fb->y_stride = drm_fb->pitches[0];
>> +	if (drm_fb->format->format == DRM_FORMAT_YVU420) {
>> +		fb->u_address = plane_state->dma_addr[2];
>> +		fb->v_address = plane_state->dma_addr[1];
>> +		fb->u_stride = drm_fb->pitches[2];
>> +		fb->v_stride = drm_fb->pitches[1];
>> +	} else {
>> +		fb->u_address = plane_state->dma_addr[1];
>> +		fb->v_address = plane_state->dma_addr[2];
>> +		fb->u_stride = drm_fb->pitches[1];
>> +		fb->v_stride = drm_fb->pitches[2];
>> +	}
>> +	fb->width = drm_rect_width(src) >> 16;
>> +	fb->height = drm_rect_height(src) >> 16;
>> +	fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
>> +	fb->rotation = to_vs_rotation(state->rotation);
>> +	fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
>> +	fb->zpos = state->zpos;
>> +	fb->enable = state->visible;
>> +	update_format(drm_fb->format->format, drm_fb->modifier, fb);
>> +	update_swizzle(drm_fb->format->format, fb);
>> +	update_watermark(plane_state->watermark, fb);
>> +	plane_state->status.tile_mode = fb->tile_mode;
>> +}
>> +
>> +static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
>> +			   struct vs_plane_state *plane_state)
>> +{
>> +	dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
>> +	plane_state->degamma_changed = false;
>> +}
>> +
>> +static void update_roi(struct vs_dc *dc, u8 id,
>> +		       struct vs_plane_state *plane_state,
>> +		       struct dc_hw_roi *roi,
>> +		       struct drm_plane_state *state)
>> +{
>> +	struct drm_vs_roi *data;
>> +	struct drm_rect *src = &state->src;
>> +	u16 src_w = drm_rect_width(src) >> 16;
>> +	u16 src_h = drm_rect_height(src) >> 16;
>> +
>> +	if (plane_state->roi) {
>> +		data = plane_state->roi->data;
>> +
>> +		if (data->enable) {
>> +			roi->x = data->roi_x;
>> +			roi->y = data->roi_y;
>> +			roi->width = (data->roi_x + data->roi_w > src_w) ?
>> +						 (src_w - data->roi_x) : data->roi_w;
>> +			roi->height = (data->roi_y + data->roi_h > src_h) ?
>> +						  (src_h - data->roi_y) : data->roi_h;
>> +			roi->enable = true;
>> +		} else {
>> +			roi->enable = false;
>> +		}
>> +
>> +		dc_hw_update_roi(&dc->hw, id, roi);
>> +	} else {
>> +		roi->enable = false;
>> +	}
>> +}
>> +
>> +static void update_color_mgmt(struct vs_dc *dc, u8 id,
>> +			      struct dc_hw_fb *fb,
>> +			      struct vs_plane_state *plane_state)
>> +{
>> +	struct drm_vs_color_mgmt *data;
>> +	struct dc_hw_colorkey colorkey;
>> +
>> +	if (plane_state->color_mgmt) {
>> +		data = plane_state->color_mgmt->data;
>> +
>> +		fb->clear_enable = data->clear_enable;
>> +		fb->clear_value = data->clear_value;
>> +
>> +		if (data->colorkey > data->colorkey_high)
>> +			data->colorkey = data->colorkey_high;
>> +
>> +		colorkey.colorkey = data->colorkey;
>> +		colorkey.colorkey_high = data->colorkey_high;
>> +		colorkey.transparency = (data->transparency) ?
>> +				DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
>> +		dc_hw_update_colorkey(&dc->hw, id, &colorkey);
>> +	}
>> +}
>> +
>> +static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			 struct drm_plane *drm_plane,
>> +			 struct drm_atomic_state *drm_state)
>> +{
>> +	struct dc_hw_fb fb = {0};
>> +	struct dc_hw_scale scale;
>> +	struct dc_hw_position pos;
>> +	struct dc_hw_blend blend;
>> +	struct dc_hw_roi roi;
>> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
>> +									   drm_plane);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> +	struct drm_rect *dest = &state->dst;
>> +	bool dec_enable = false;
>> +	u8 display_id = 0;
>> +
>> +	display_id = to_vs_display_id(dc, state->crtc);
>> +	update_fb(plane, display_id, &fb, state);
>> +	fb.dec_enable = dec_enable;
>> +
>> +	update_roi(dc, plane->id, plane_state, &roi, state);
>> +
>> +	update_scale(state, &roi, &scale);
>> +
>> +	if (plane_state->degamma_changed)
>> +		update_degamma(dc, plane, plane_state);
>> +
>> +	pos.start_x = dest->x1;
>> +	pos.start_y = dest->y1;
>> +	pos.end_x = dest->x2;
>> +	pos.end_y = dest->y2;
>> +
>> +	blend.alpha = (u8)(state->alpha >> 8);
>> +	blend.blend_mode = (u8)(state->pixel_blend_mode);
>> +
>> +	update_color_mgmt(dc, plane->id, &fb, plane_state);
>> +
>> +	dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
>> +}
>> +
>> +static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
>> +		       struct drm_plane *drm_plane,
>> +		       struct drm_atomic_state *drm_state)
>> +{
>> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
>> +									   drm_plane);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> +	struct drm_vs_watermark *data;
>> +	struct dc_hw_qos qos;
>> +
>> +	if (plane_state->watermark) {
>> +		data = plane_state->watermark->data;
>> +
>> +		if (data->qos_high) {
>> +			if (data->qos_low > data->qos_high)
>> +				data->qos_low = data->qos_high;
>> +
>> +			qos.low_value = data->qos_low & 0x0F;
>> +			qos.high_value = data->qos_high & 0x0F;
>> +			dc_hw_update_qos(&dc->hw, &qos);
>> +		}
>> +	}
>> +}
>> +
>> +static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
>> +{
>> +	u8 size_type;
>> +
>> +	switch (state->crtc_w) {
>> +	case 32:
>> +		size_type = CURSOR_SIZE_32X32;
>> +		break;
>> +	case 64:
>> +		size_type = CURSOR_SIZE_64X64;
>> +		break;
>> +	default:
>> +		size_type = CURSOR_SIZE_32X32;
>> +		break;
>> +	}
>> +
>> +	cursor->size = size_type;
>> +}
>> +
>> +static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +				struct drm_plane *drm_plane,
>> +				struct drm_atomic_state *drm_state)
>> +{
>> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
>> +								       drm_plane);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> +	struct drm_framebuffer *drm_fb = state->fb;
>> +	struct dc_hw_cursor cursor;
>> +
>> +	cursor.address = plane_state->dma_addr[0];
>> +	cursor.x = state->crtc_x;
>> +	cursor.y = state->crtc_y;
>> +	cursor.hot_x = drm_fb->hot_x;
>> +	cursor.hot_y = drm_fb->hot_y;
>> +	cursor.display_id = to_vs_display_id(dc, state->crtc);
>> +	update_cursor_size(state, &cursor);
>> +	cursor.enable = true;
>> +
>> +	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
>> +}
>> +
>> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			struct drm_plane *drm_plane,
>> +			struct drm_atomic_state *drm_state)
>> +{
>> +	update_plane(dc, plane, drm_plane, drm_state);
>> +	update_qos(dc, plane, drm_plane, drm_state);
>> +}
>> +
>> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			       struct drm_plane *drm_plane,
>> +			       struct drm_atomic_state *drm_state)
>> +{
>> +	update_cursor_plane(dc, plane, drm_plane, drm_state);
>> +}
>> +
>> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			 struct drm_plane_state *old_state)
>> +{
>> +	struct dc_hw_fb fb = {0};
>> +
>> +	fb.enable = false;
>> +	dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
>> +}
>> +
>> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +				struct drm_plane_state *old_state)
>> +{
>> +	struct dc_hw_cursor cursor = {0};
>> +
>> +	cursor.enable = false;
>> +	cursor.display_id = to_vs_display_id(dc, old_state->crtc);
>> +	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
>> +}
>> +
>> +static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
>> +				u64 modifier)
>> +{
>> +	const u64 *mods;
>> +
>> +	if (!plane_info->modifiers)
>> +		return false;
>> +
>> +	for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
>> +		if (*mods == modifier)
>> +			return true;
>> +	}
>> +
>> +	return false;
>> +}
>> +
>> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
>> +		      struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> +										 plane);
>> +
>> +	struct drm_framebuffer *fb = new_plane_state->fb;
>> +	const struct vs_plane_info *plane_info;
>> +	struct drm_crtc *crtc = new_plane_state->crtc;
>> +	struct drm_crtc_state *crtc_state;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +
>> +	plane_info = &dc->hw.info->planes[vs_plane->id];
>> +
>> +	if (fb->width < plane_info->min_width ||
>> +	    fb->width > plane_info->max_width ||
>> +	    fb->height < plane_info->min_height ||
>> +	    fb->height > plane_info->max_height)
>> +		drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
>> +			     vs_plane->id);
>> +
>> +	if (!vs_dc_mod_supported(plane_info, fb->modifier)) {
>> +		drm_err(plane->dev, "unsupported modifier on plane%d.\n", vs_plane->id);
>> +		return -EINVAL;
>> +	}
>> +
>> +	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
>> +	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
>> +						  plane_info->min_scale,
>> +						  plane_info->max_scale,
>> +						  true, true);
>> +}
>> +
>> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
>> +			     struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> +									   plane);
>> +	struct drm_framebuffer *fb = new_plane_state->fb;
>> +	const struct vs_plane_info *plane_info;
>> +	struct drm_crtc *crtc = new_plane_state->crtc;
>> +	struct drm_crtc_state *crtc_state;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +
>> +	plane_info = &dc->hw.info->planes[vs_plane->id];
>> +
>> +	if (fb->width < plane_info->min_width ||
>> +	    fb->width > plane_info->max_width ||
>> +	    fb->height < plane_info->min_height ||
>> +	    fb->height > plane_info->max_height)
>> +		drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", vs_plane->id);
>> +
>> +	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
>> +	if (IS_ERR(crtc_state))
>> +		return -EINVAL;
>> +
>> +	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
>> +						plane_info->min_scale,
>> +						plane_info->max_scale,
>> +						true, true);
>> +}
>> +
>> +static void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
>> +{
>> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
>> +
>> +	drm_crtc_handle_vblank(crtc);
>> +
>> +	vs_crtc_state->underflow = underflow;
>> +}
>> +
>> +static irqreturn_t dc_isr(int irq, void *data)
>> +{
>> +	struct vs_dc *dc = data;
>> +	struct vs_dc_info *dc_info = dc->hw.info;
>> +	u32 i, ret;
>> +
>> +	ret = dc_hw_get_interrupt(&dc->hw);
>> +
>> +	for (i = 0; i < dc_info->panel_num; i++)
>> +		vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +void vs_dc_commit(struct vs_dc *dc)
>> +{
>> +	dc_hw_enable_shadow_register(&dc->hw, false);
>> +
>> +	dc_hw_commit(&dc->hw);
>> +
>> +	if (dc->first_frame)
>> +		dc->first_frame = false;
>> +
>> +	dc_hw_enable_shadow_register(&dc->hw, true);
>> +}
>> +
>> +static int dc_bind(struct device *dev, struct device *master, void *data)
>> +{
>> +	struct drm_device *drm_dev = data;
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +	struct device_node *port;
>> +	struct vs_crtc *crtc;
>> +	struct vs_dc_info *dc_info;
>> +	struct vs_plane *plane;
>> +	struct vs_plane_info *plane_info;
>> +	int i, ret;
>> +	u32 ctrc_mask = 0;
>> +
>> +	if (!drm_dev || !dc) {
>> +		dev_err(dev, "devices are not created.\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	ret = dc_init(dev);
>> +	if (ret < 0) {
>> +		drm_err(drm_dev, "Failed to initialize DC hardware.\n");
>> +		return ret;
>> +	}
>> +
>> +	port = of_get_child_by_name(dev->of_node, "port");
>> +	if (!port) {
>> +		drm_err(drm_dev, "no port node found\n");
>> +		return -ENODEV;
>> +	}
>> +	of_node_put(port);
>> +
>> +	dc_info = dc->hw.info;
>> +
>> +	for (i = 0; i < dc_info->panel_num; i++) {
>> +		crtc = vs_crtc_create(drm_dev, dc_info);
>> +		if (!crtc) {
>> +			drm_err(drm_dev, "Failed to create CRTC.\n");
>> +			ret = -ENOMEM;
>> +			return ret;
>> +		}
>> +
>> +		crtc->base.port = port;
>> +		crtc->dev = dev;
>> +		dc->crtc[i] = crtc;
>> +		ctrc_mask |= drm_crtc_mask(&crtc->base);
>> +	}
>> +
>> +	for (i = 0; i < dc_info->plane_num; i++) {
>> +		plane_info = (struct vs_plane_info *)&dc_info->planes[i];
>> +
>> +		if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
>> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
>> +						drm_crtc_mask(&dc->crtc[0]->base));
>> +		} else if (!strcmp(plane_info->name, "Primary_1") ||
>> +				   !strcmp(plane_info->name, "Cursor_1")) {
>> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
>> +						drm_crtc_mask(&dc->crtc[1]->base));
> 
> I'd say, it's not typical to use name to distinguish objects. Maybe you 
> can add indices to the info structure and drop the names instead?
> 
> 
>> +		} else {
>> +			plane = vs_plane_create(drm_dev, plane_info,
>> +						dc_info->layer_num, ctrc_mask);
>> +		}
>> +
>> +		if (IS_ERR(plane)) {
>> +			dev_err(dev, "failed to construct plane\n");
>> +			return PTR_ERR(plane);
>> +		}
>> +
>> +		plane->id = i;
>> +		dc->planes[i].id = plane_info->id;
>> +
>> +		if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
>> +			if (!strcmp(plane_info->name, "Primary"))
>> +				dc->crtc[0]->base.primary = &plane->base;
>> +			else
>> +				dc->crtc[1]->base.primary = &plane->base;
> 
> This definitely urges for an index in the plane info / plane_state.
> 
>> +			drm_dev->mode_config.min_width = plane_info->min_width;
>> +			drm_dev->mode_config.min_height =
>> +							plane_info->min_height;
>> +			drm_dev->mode_config.max_width = plane_info->max_width;
>> +			drm_dev->mode_config.max_height =
>> +							plane_info->max_height;
>> +		}
>> +
>> +		if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
>> +			if (!strcmp(plane_info->name, "Cursor"))
>> +				dc->crtc[0]->base.cursor = &plane->base;
>> +			else
>> +				dc->crtc[1]->base.cursor = &plane->base;
>> +			drm_dev->mode_config.cursor_width =
>> +							plane_info->max_width;
>> +			drm_dev->mode_config.cursor_height =
>> +							plane_info->max_height;
>> +		}
>> +	}
>> +
>> +	vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
>> +	return 0;
>> +}
>> +
>> +static void dc_unbind(struct device *dev, struct device *master, void *data)
>> +{
>> +	dc_deinit(dev);
>> +}
>> +
>> +const struct component_ops dc_component_ops = {
>> +	.bind = dc_bind,
>> +	.unbind = dc_unbind,
>> +};
>> +
>> +static const struct of_device_id dc_driver_dt_match[] = {
>> +	{ .compatible = "starfive,jh7110-dc8200", },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
>> +
>> +static int dc_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct vs_dc *dc;
>> +	int irq, ret, i;
>> +
>> +	dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
>> +	if (!dc)
>> +		return -ENOMEM;
>> +
>> +	dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
>> +	if (IS_ERR(dc->hw.hi_base))
>> +		return PTR_ERR(dc->hw.hi_base);
>> +
>> +	dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
>> +	if (IS_ERR(dc->hw.reg_base))
>> +		return PTR_ERR(dc->hw.reg_base);
>> +
>> +	dc->nclks = ARRAY_SIZE(dc->clk_vout);
>> +	for (i = 0; i < dc->nclks; ++i)
>> +		dc->clk_vout[i].id = vout_clocks[i];
>> +	ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to get clk controls\n");
>> +		return ret;
>> +	}
>> +
>> +	dc->nrsts = ARRAY_SIZE(dc->rst_vout);
>> +	for (i = 0; i < dc->nrsts; ++i)
>> +		dc->rst_vout[i].id = vout_resets[i];
>> +	ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
>> +						 dc->rst_vout);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to get reset controls\n");
>> +		return ret;
>> +	}
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +
>> +	ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
> 
> Are you ready to handle the IRQ at this point?
> 
>> +	if (ret < 0) {
>> +		dev_err(dev, "Failed to install irq:%u.\n", irq);
>> +		return ret;
>> +	}
>> +
>> +	dev_set_drvdata(dev, dc);
>> +
>> +	return component_add(dev, &dc_component_ops);
>> +}
>> +
>> +static int dc_remove(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +
>> +	component_del(dev, &dc_component_ops);
>> +
>> +	dev_set_drvdata(dev, NULL);
>> +
>> +	return 0;
>> +}
>> +
>> +struct platform_driver dc_platform_driver = {
>> +	.probe = dc_probe,
>> +	.remove = dc_remove,
>> +	.driver = {
>> +		.name = "vs-dc",
>> +		.of_match_table = of_match_ptr(dc_driver_dt_match),
>> +	},
>> +};
>> +
>> +MODULE_AUTHOR("StarFive Corporation");
>> +MODULE_DESCRIPTION("VeriSilicon DC Driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
>> new file mode 100644
>> index 000000000..8e96fd32c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_dc.h
>> @@ -0,0 +1,80 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_DC_H__
>> +#define __VS_DC_H__
>> +
>> +#include <linux/clk.h>
>> +#include <linux/mm_types.h>
>> +#include <linux/reset.h>
>> +
>> +#include <drm/drm_fourcc.h>
>> +#include <drm/drm_modes.h>
>> +
>> +#include "vs_crtc.h"
>> +#include "vs_dc_hw.h"
>> +#include "vs_plane.h"
>> +
>> +struct vs_dc_plane {
>> +	enum dc_hw_plane_id id;
>> +};
>> +
>> +enum vout_clk {
>> +	CLK_VOUT_NOC_DISP = 0,
>> +	CLK_VOUT_PIX0,
>> +	CLK_VOUT_PIX1,
>> +	CLK_VOUT_CORE,
>> +	CLK_VOUT_AXI,
>> +	CLK_VOUT_AHB,
>> +	CLK_VOUT_HDMI_PIX,
>> +	CLK_VOUT_SOC_PIX,
>> +	CLK_VOUT_NUM
>> +};
>> +
>> +enum rst_vout {
>> +	RST_VOUT_AXI = 0,
>> +	RST_VOUT_AHB,
>> +	RST_VOUT_CORE,
>> +	RST_VOUT_NUM
>> +};
>> +
>> +struct vs_dc {
>> +	struct vs_crtc		*crtc[DC_DISPLAY_NUM];
>> +	struct dc_hw		hw;
>> +	bool			first_frame;
>> +
>> +	struct vs_dc_plane	planes[PLANE_NUM];
>> +	struct clk_bulk_data	clk_vout[CLK_VOUT_NUM];
>> +	int			nclks;
>> +	struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
>> +	int			nrsts;
>> +};
>> +
>> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc);
>> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc);
>> +
>> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
>> +		     struct drm_color_lut *lut, unsigned int size);
>> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc, bool enable);
>> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable);
>> +void vs_dc_commit(struct vs_dc *dc);
>> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			struct drm_plane *drm_plane,
>> +			struct drm_atomic_state *drm_state);
>> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			 struct drm_plane_state *old_state);
>> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
>> +		      struct drm_atomic_state *state);
>> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +			       struct drm_plane *drm_plane,
>> +			       struct drm_atomic_state *drm_state);
>> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> +				struct drm_plane_state *old_state);
>> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
>> +			     struct drm_atomic_state *state);
>> +
>> +extern struct platform_driver dc_platform_driver;
>> +
>> +#endif /* __VS_DC_H__ */
>> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
>> new file mode 100644
>> index 000000000..e5acb7eb4
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
>> @@ -0,0 +1,1959 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#include <linux/bits.h>
>> +#include <linux/io.h>
>> +#include <linux/media-bus-format.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_blend.h>
>> +#include <drm/drm_fourcc.h>
>> +#include <drm/vs_drm.h>
>> +
>> +#include "vs_dc_hw.h"
>> +#include "vs_type.h"
>> +
>> +static const u32 horkernel[] = {
>> +	0x00000000, 0x20000000, 0x00002000, 0x00000000,
>> +	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
>> +	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
>> +	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
>> +	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
>> +	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
>> +	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
>> +	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
>> +	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
>> +	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
>> +	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
>> +	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
>> +	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
>> +	0x00000000, 0x00000000, 0x00000000, 0x01470000,
>> +	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
>> +	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
>> +	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
>> +	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
>> +	0x00000000, 0x00000000, 0x00004000, 0x00000000,
>> +	0x00000000, 0x00000000, 0x20002000, 0x00000000,
>> +	0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
>> +	0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
>> +	0x00000000, 0x00000000, 0x00000000, 0x14680000,
>> +	0x00002b98, 0x00000000, 0x00000000, 0x00000000,
>> +	0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
>> +	0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
>> +	0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
>> +	0x00000000, 0x087f0000, 0x00003781, 0x00000000,
>> +	0x00000000, 0x00000000, 0x399a0666, 0x00000000,
>> +	0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
>> +	0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
>> +	0x00000000, 0x00000000, 0x00000000, 0x021f0000,
>> +};
>> +
>> +#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))
>> +
>> +static const u32 verkernel[] = {
>> +	0x00000000, 0x20000000, 0x00002000, 0x00000000,
>> +	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
>> +	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
>> +	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
>> +	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
>> +	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
>> +	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
>> +	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
>> +	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
>> +	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
>> +	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
>> +	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
>> +	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
>> +	0x00000000, 0x00000000, 0x00000000, 0x01470000,
>> +	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
>> +	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
>> +	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
>> +	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
>> +	0x00000000, 0x00000000, 0x00004000, 0x00000000,
>> +	0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
>> +	0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
>> +	0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> +};
>> +
>> +#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))
>> +
>> +/*
>> + * RGB 709->2020 conversion parameters
>> + */
>> +static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
>> +	10279,	5395,	709,
>> +	1132,	15065,	187,
>> +	269,	1442,	14674
>> +};
>> +
>> +/*
>> + * YUV601 to RGB conversion parameters
>> + * YUV2RGB[0]  - [8] : C0 - C8;
>> + * YUV2RGB[9]  - [11]: D0 - D2;
>> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
>> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
>> + */
>> +static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
>> +	1196,	0,			1640,	1196,
>> +	-404,	-836,		1196,	2076,
>> +	0,		-916224,	558336,	-1202944,
>> +	64,		 940,		64,		960
>> +};
>> +
>> +/*
>> + * YUV709 to RGB conversion parameters
>> + * YUV2RGB[0]  - [8] : C0 - C8;
>> + * YUV2RGB[9]  - [11]: D0 - D2;
>> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
>> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
>> + */
>> +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
>> +	1196,		0,		1844,	1196,
>> +	-220,		-548,	1196,	2172,
>> +	0,			-1020672, 316672,  -1188608,
>> +	64,			940,		64,		960
>> +};
>> +
>> +/*
>> + * YUV2020 to RGB conversion parameters
>> + * YUV2RGB[0]  - [8] : C0 - C8;
>> + * YUV2RGB[9]  - [11]: D0 - D2;
>> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
>> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
>> + */
>> +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
>> +	1196, 0, 1724, 1196,
>> +	-192, -668, 1196, 2200,
>> +	0, -959232, 363776, -1202944,
>> +	64, 940, 64, 960
>> +};
>> +
>> +/*
>> + * RGB to YUV2020 conversion parameters
>> + * RGB2YUV[0] - [8] : C0 - C8;
>> + * RGB2YUV[9] - [11]: D0 - D2;
>> + */
>> +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
>> +	230,	594,	52,
>> +	-125,  -323,	448,
>> +	448,   -412,   -36,
>> +	64,		512,	512
>> +};
>> +
>> +/*
>> + * Degamma table for 709 color space data.
>> + */
>> +static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
>> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
>> +	0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
>> +	0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
>> +	0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
>> +	0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
>> +	0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
>> +	0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
>> +	0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
>> +	0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
>> +	0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
>> +	0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
>> +	0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
>> +	0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
>> +	0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
>> +	0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
>> +	0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
>> +	0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
>> +	0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
>> +	0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
>> +	0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
>> +	0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
>> +	0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
>> +	0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
>> +	0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
>> +	0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
>> +	0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
>> +	0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
>> +	0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
>> +	0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
>> +	0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
>> +	0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
>> +	0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
>> +	0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
>> +};
>> +
>> +/*
>> + * Degamma table for 2020 color space data.
>> + */
>> +static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
>> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
>> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
>> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
>> +	0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
>> +	0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
>> +	0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
>> +	0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
>> +	0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
>> +	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
>> +	0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
>> +	0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
>> +	0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
>> +	0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
>> +	0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
>> +	0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
>> +	0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
>> +	0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
>> +	0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
>> +	0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
>> +	0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
>> +	0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
>> +	0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
>> +	0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
>> +	0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
>> +	0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
>> +	0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
>> +	0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
>> +	0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
>> +	0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
>> +	0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
>> +	0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
>> +	0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
>> +	0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
>> +};
>> +
>> +/* one is for primary plane and the other is for all overlay planes */
>> +static const struct dc_hw_plane_reg dc_plane_reg[] = {
>> +	{
>> +	.y_address		= DC_FRAMEBUFFER_ADDRESS,
>> +	.u_address		= DC_FRAMEBUFFER_U_ADDRESS,
>> +	.v_address		= DC_FRAMEBUFFER_V_ADDRESS,
>> +	.y_stride		= DC_FRAMEBUFFER_STRIDE,
>> +	.u_stride		= DC_FRAMEBUFFER_U_STRIDE,
>> +	.v_stride		= DC_FRAMEBUFFER_V_STRIDE,
>> +	.size			= DC_FRAMEBUFFER_SIZE,
>> +	.top_left		= DC_FRAMEBUFFER_TOP_LEFT,
>> +	.bottom_right	= DC_FRAMEBUFFER_BOTTOM_RIGHT,
>> +	.scale_factor_x			= DC_FRAMEBUFFER_SCALE_FACTOR_X,
>> +	.scale_factor_y			= DC_FRAMEBUFFER_SCALE_FACTOR_Y,
>> +	.h_filter_coef_index	= DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
>> +	.h_filter_coef_data		= DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
>> +	.v_filter_coef_index	= DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
>> +	.v_filter_coef_data		= DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
>> +	.init_offset			= DC_FRAMEBUFFER_INIT_OFFSET,
>> +	.color_key				= DC_FRAMEBUFFER_COLOR_KEY,
>> +	.color_key_high			= DC_FRAMEBUFFER_COLOR_KEY_HIGH,
>> +	.clear_value			= DC_FRAMEBUFFER_CLEAR_VALUE,
>> +	.color_table_index		= DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
>> +	.color_table_data		= DC_FRAMEBUFFER_COLOR_TABLE_DATA,
>> +	.scale_config			= DC_FRAMEBUFFER_SCALE_CONFIG,
>> +	.water_mark				= DC_FRAMEBUFFER_WATER_MARK,
>> +	.degamma_index			= DC_FRAMEBUFFER_DEGAMMA_INDEX,
>> +	.degamma_data			= DC_FRAMEBUFFER_DEGAMMA_DATA,
>> +	.degamma_ex_data		= DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
>> +	.src_global_color		= DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
>> +	.dst_global_color		= DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
>> +	.blend_config			= DC_FRAMEBUFFER_BLEND_CONFIG,
>> +	.roi_origin				= DC_FRAMEBUFFER_ROI_ORIGIN,
>> +	.roi_size				= DC_FRAMEBUFFER_ROI_SIZE,
>> +	.yuv_to_rgb_coef0			= DC_FRAMEBUFFER_YUVTORGB_COEF0,
>> +	.yuv_to_rgb_coef1			= DC_FRAMEBUFFER_YUVTORGB_COEF1,
>> +	.yuv_to_rgb_coef2			= DC_FRAMEBUFFER_YUVTORGB_COEF2,
>> +	.yuv_to_rgb_coef3			= DC_FRAMEBUFFER_YUVTORGB_COEF3,
>> +	.yuv_to_rgb_coef4			= DC_FRAMEBUFFER_YUVTORGB_COEF4,
>> +	.yuv_to_rgb_coefd0			= DC_FRAMEBUFFER_YUVTORGB_COEFD0,
>> +	.yuv_to_rgb_coefd1			= DC_FRAMEBUFFER_YUVTORGB_COEFD1,
>> +	.yuv_to_rgb_coefd2			= DC_FRAMEBUFFER_YUVTORGB_COEFD2,
>> +	.y_clamp_bound				= DC_FRAMEBUFFER_Y_CLAMP_BOUND,
>> +	.uv_clamp_bound				= DC_FRAMEBUFFER_UV_CLAMP_BOUND,
>> +	.rgb_to_rgb_coef0			= DC_FRAMEBUFFER_RGBTORGB_COEF0,
>> +	.rgb_to_rgb_coef1			= DC_FRAMEBUFFER_RGBTORGB_COEF1,
>> +	.rgb_to_rgb_coef2			= DC_FRAMEBUFFER_RGBTORGB_COEF2,
>> +	.rgb_to_rgb_coef3			= DC_FRAMEBUFFER_RGBTORGB_COEF3,
>> +	.rgb_to_rgb_coef4			= DC_FRAMEBUFFER_RGBTORGB_COEF4,
>> +	},
>> +	{
>> +	.y_address		= DC_OVERLAY_ADDRESS,
>> +	.u_address		= DC_OVERLAY_U_ADDRESS,
>> +	.v_address		= DC_OVERLAY_V_ADDRESS,
>> +	.y_stride		= DC_OVERLAY_STRIDE,
>> +	.u_stride		= DC_OVERLAY_U_STRIDE,
>> +	.v_stride		= DC_OVERLAY_V_STRIDE,
>> +	.size			= DC_OVERLAY_SIZE,
>> +	.top_left		= DC_OVERLAY_TOP_LEFT,
>> +	.bottom_right	= DC_OVERLAY_BOTTOM_RIGHT,
>> +	.scale_factor_x	= DC_OVERLAY_SCALE_FACTOR_X,
>> +	.scale_factor_y	= DC_OVERLAY_SCALE_FACTOR_Y,
>> +	.h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
>> +	.h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
>> +	.v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
>> +	.v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
>> +	.init_offset		 = DC_OVERLAY_INIT_OFFSET,
>> +	.color_key			 = DC_OVERLAY_COLOR_KEY,
>> +	.color_key_high			= DC_OVERLAY_COLOR_KEY_HIGH,
>> +	.clear_value		 = DC_OVERLAY_CLEAR_VALUE,
>> +	.color_table_index	 = DC_OVERLAY_COLOR_TABLE_INDEX,
>> +	.color_table_data	 = DC_OVERLAY_COLOR_TABLE_DATA,
>> +	.scale_config		 = DC_OVERLAY_SCALE_CONFIG,
>> +	.water_mark				= DC_OVERLAY_WATER_MARK,
>> +	.degamma_index		 = DC_OVERLAY_DEGAMMA_INDEX,
>> +	.degamma_data		 = DC_OVERLAY_DEGAMMA_DATA,
>> +	.degamma_ex_data	 = DC_OVERLAY_DEGAMMA_EX_DATA,
>> +	.src_global_color	 = DC_OVERLAY_SRC_GLOBAL_COLOR,
>> +	.dst_global_color	 = DC_OVERLAY_DST_GLOBAL_COLOR,
>> +	.blend_config		 = DC_OVERLAY_BLEND_CONFIG,
>> +	.roi_origin				= DC_OVERLAY_ROI_ORIGIN,
>> +	.roi_size				= DC_OVERLAY_ROI_SIZE,
>> +	.yuv_to_rgb_coef0		 = DC_OVERLAY_YUVTORGB_COEF0,
>> +	.yuv_to_rgb_coef1		 = DC_OVERLAY_YUVTORGB_COEF1,
>> +	.yuv_to_rgb_coef2		 = DC_OVERLAY_YUVTORGB_COEF2,
>> +	.yuv_to_rgb_coef3		 = DC_OVERLAY_YUVTORGB_COEF3,
>> +	.yuv_to_rgb_coef4			= DC_OVERLAY_YUVTORGB_COEF4,
>> +	.yuv_to_rgb_coefd0			= DC_OVERLAY_YUVTORGB_COEFD0,
>> +	.yuv_to_rgb_coefd1			= DC_OVERLAY_YUVTORGB_COEFD1,
>> +	.yuv_to_rgb_coefd2			= DC_OVERLAY_YUVTORGB_COEFD2,
>> +	.y_clamp_bound		 = DC_OVERLAY_Y_CLAMP_BOUND,
>> +	.uv_clamp_bound		 = DC_OVERLAY_UV_CLAMP_BOUND,
>> +	.rgb_to_rgb_coef0		 = DC_OVERLAY_RGBTORGB_COEF0,
>> +	.rgb_to_rgb_coef1		 = DC_OVERLAY_RGBTORGB_COEF1,
>> +	.rgb_to_rgb_coef2		 = DC_OVERLAY_RGBTORGB_COEF2,
>> +	.rgb_to_rgb_coef3		 = DC_OVERLAY_RGBTORGB_COEF3,
>> +	.rgb_to_rgb_coef4		 = DC_OVERLAY_RGBTORGB_COEF4,
>> +	},
>> +};
>> +
>> +static const u32 primary_overlay_format0[] = {
>> +	DRM_FORMAT_XRGB4444,
>> +	DRM_FORMAT_XBGR4444,
>> +	DRM_FORMAT_RGBX4444,
>> +	DRM_FORMAT_BGRX4444,
>> +	DRM_FORMAT_ARGB4444,
>> +	DRM_FORMAT_ABGR4444,
>> +	DRM_FORMAT_RGBA4444,
>> +	DRM_FORMAT_BGRA4444,
>> +	DRM_FORMAT_XRGB1555,
>> +	DRM_FORMAT_XBGR1555,
>> +	DRM_FORMAT_RGBX5551,
>> +	DRM_FORMAT_BGRX5551,
>> +	DRM_FORMAT_ARGB1555,
>> +	DRM_FORMAT_ABGR1555,
>> +	DRM_FORMAT_RGBA5551,
>> +	DRM_FORMAT_BGRA5551,
>> +	DRM_FORMAT_RGB565,
>> +	DRM_FORMAT_BGR565,
>> +	DRM_FORMAT_XRGB8888,
>> +	DRM_FORMAT_XBGR8888,
>> +	DRM_FORMAT_RGBX8888,
>> +	DRM_FORMAT_BGRX8888,
>> +	DRM_FORMAT_ARGB8888,
>> +	DRM_FORMAT_ABGR8888,
>> +	DRM_FORMAT_RGBA8888,
>> +	DRM_FORMAT_BGRA8888,
>> +	DRM_FORMAT_ARGB2101010,
>> +	DRM_FORMAT_ABGR2101010,
>> +	DRM_FORMAT_RGBA1010102,
>> +	DRM_FORMAT_BGRA1010102,
>> +	DRM_FORMAT_YUYV,
>> +	DRM_FORMAT_YVYU,
>> +	DRM_FORMAT_UYVY,
>> +	DRM_FORMAT_VYUY,
>> +	DRM_FORMAT_YVU420,
>> +	DRM_FORMAT_YUV420,
>> +	DRM_FORMAT_NV12,
>> +	DRM_FORMAT_NV21,
>> +	DRM_FORMAT_NV16,
>> +	DRM_FORMAT_NV61,
>> +	DRM_FORMAT_P010,
>> +};
>> +
>> +static const u32 primary_overlay_format1[] = {
>> +	DRM_FORMAT_XRGB8888,
>> +	DRM_FORMAT_XBGR8888,
>> +	DRM_FORMAT_RGBX8888,
>> +	DRM_FORMAT_BGRX8888,
>> +	DRM_FORMAT_ARGB8888,
>> +	DRM_FORMAT_ABGR8888,
>> +	DRM_FORMAT_RGBA8888,
>> +	DRM_FORMAT_BGRA8888,
>> +	DRM_FORMAT_ARGB2101010,
>> +	DRM_FORMAT_ABGR2101010,
>> +	DRM_FORMAT_RGBA1010102,
>> +	DRM_FORMAT_BGRA1010102,
>> +	DRM_FORMAT_NV12,
>> +	DRM_FORMAT_NV21,
>> +	DRM_FORMAT_YUV444,
>> +};
>> +
>> +static const u32 cursor_formats[] = {
>> +	DRM_FORMAT_ARGB8888
>> +};
>> +
>> +static const u64 format_modifier0[] = {
>> +	DRM_FORMAT_MOD_LINEAR,
>> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X8),
>> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_8X8),
>> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X8),
>> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X4),
>> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X4),
>> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_4X8),
>> +	DRM_FORMAT_MOD_INVALID
>> +};
>> +
>> +static const u64 secondary_format_modifiers[] = {
>> +	DRM_FORMAT_MOD_LINEAR,
>> +	DRM_FORMAT_MOD_INVALID
>> +};
>> +
>> +#define FRAC_16_16(mult, div)	 (((mult) << 16) / (div))
>> +
>> +static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {
>> +	{
>> +		/* DC_REV_0 */
>> +		{
>> +		.name			= "Primary",
> 
> I'd say that the indentation is strange here.
> It might be more scalable to split a single array into per-generation 
> data structures and reference them directly from the info struct.
> 
>> +		.id				= PRIMARY_PLANE_0,
>> +		.type			= DRM_PLANE_TYPE_PRIMARY,
>> +		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
>> +		.formats		= primary_overlay_format0,
>> +		.num_modifiers	= ARRAY_SIZE(format_modifier0),
>> +		.modifiers		= format_modifier0,
>> +		.min_width		= 0,
>> +		.min_height		= 0,
>> +		.max_width		= 4096,
>> +		.max_height		= 4096,
>> +		.rotation		= DRM_MODE_ROTATE_0 |
>> +							DRM_MODE_ROTATE_90 |
>> +							DRM_MODE_ROTATE_180 |
>> +							DRM_MODE_ROTATE_270 |
>> +							DRM_MODE_REFLECT_X |
>> +							DRM_MODE_REFLECT_Y,
>> +		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +							BIT(DRM_MODE_BLEND_PREMULTI) |
>> +							BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 0,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name			= "Overlay",
>> +		.id				= OVERLAY_PLANE_0,
>> +		.type			= DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
>> +		.formats		= primary_overlay_format0,
>> +		.num_modifiers	= ARRAY_SIZE(format_modifier0),
>> +		.modifiers		= format_modifier0,
>> +		.min_width		= 0,
>> +		.min_height		= 0,
>> +		.max_width		= 4096,
>> +		.max_height		= 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 1,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name			= "Overlay_1",
>> +		.id				= OVERLAY_PLANE_1,
>> +		.type			= DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
>> +		.formats		= primary_overlay_format0,
>> +		.num_modifiers	= ARRAY_SIZE(secondary_format_modifiers),
>> +		.modifiers		= secondary_format_modifiers,
>> +		.min_width		= 0,
>> +		.min_height		= 0,
>> +		.max_width		= 4096,
>> +		.max_height		= 4096,
>> +		.rotation		= 0,
>> +		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +							BIT(DRM_MODE_BLEND_PREMULTI) |
>> +							BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 2,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Primary_1",
>> +		.id				= PRIMARY_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 3,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay_2",
>> +		.id				= OVERLAY_PLANE_2,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 4,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay_3",
>> +		.id			= OVERLAY_PLANE_3,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
>> +		.modifiers	 = secondary_format_modifiers,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = 0,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 5,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Cursor",
>> +		.id				= CURSOR_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_CURSOR,
>> +		.num_formats = ARRAY_SIZE(cursor_formats),
>> +		.formats	 = cursor_formats,
>> +		.num_modifiers = 0,
>> +		.modifiers	 = NULL,
>> +		.min_width	 = 32,
>> +		.min_height  = 32,
>> +		.max_width	 = 64,
>> +		.max_height  = 64,
>> +		.rotation	 = 0,
>> +		.degamma_size = 0,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 255,
>> +		.watermark	 = false,
>> +		.color_mgmt  = false,
>> +		.roi		 = false,
>> +		},
>> +		{
>> +		.name		 = "Cursor_1",
>> +		.id				= CURSOR_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_CURSOR,
>> +		.num_formats = ARRAY_SIZE(cursor_formats),
>> +		.formats	 = cursor_formats,
>> +		.num_modifiers = 0,
>> +		.modifiers	 = NULL,
>> +		.min_width	 = 32,
>> +		.min_height  = 32,
>> +		.max_width	 = 64,
>> +		.max_height  = 64,
>> +		.rotation	 = 0,
>> +		.degamma_size = 0,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 255,
>> +		.watermark	 = false,
>> +		.color_mgmt  = false,
>> +		.roi		 = false,
>> +		},
>> +	},
>> +	{
>> +		/* DC_REV_1 */
>> +		{
>> +		.name		 = "Primary",
>> +		.id				= PRIMARY_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 0,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay",
>> +		.id				= OVERLAY_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 1,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Primary_1",
>> +		.id				= PRIMARY_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 2,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay_2",
>> +		.id				= OVERLAY_PLANE_2,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format0),
>> +		.formats	 = primary_overlay_format0,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 3,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Cursor",
>> +		.id				= CURSOR_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_CURSOR,
>> +		.num_formats = ARRAY_SIZE(cursor_formats),
>> +		.formats	 = cursor_formats,
>> +		.num_modifiers = 0,
>> +		.modifiers	 = NULL,
>> +		.min_width	 = 32,
>> +		.min_height  = 32,
>> +		.max_width	 = 64,
>> +		.max_height  = 64,
>> +		.rotation	 = 0,
>> +		.degamma_size = 0,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 255,
>> +		.watermark	 = false,
>> +		.color_mgmt  = false,
>> +		.roi		 = false,
>> +		},
>> +		{
>> +		.name		 = "Cursor_1",
>> +		.id				= CURSOR_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_CURSOR,
>> +		.num_formats = ARRAY_SIZE(cursor_formats),
>> +		.formats	 = cursor_formats,
>> +		.num_modifiers = 0,
>> +		.modifiers	 = NULL,
>> +		.min_width	 = 32,
>> +		.min_height  = 32,
>> +		.max_width	 = 64,
>> +		.max_height  = 64,
>> +		.rotation	 = 0,
>> +		.degamma_size = 0,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 255,
>> +		.watermark	 = false,
>> +		.color_mgmt  = false,
>> +		.roi		 = false,
>> +		},
>> +	},
>> +	{
>> +		/* DC_REV_2 */
>> +		{
>> +		.name		 = "Primary",
>> +		.id				= PRIMARY_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
>> +		.formats	 = primary_overlay_format1,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 0,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay",
>> +		.id				= OVERLAY_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
>> +		.formats	 = primary_overlay_format1,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 1,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay_1",
>> +		.id				= OVERLAY_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
>> +		.formats	 = primary_overlay_format1,
>> +		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
>> +		.modifiers	 = secondary_format_modifiers,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = 0,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 2,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Primary_1",
>> +		.id				= PRIMARY_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_PRIMARY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
>> +		.formats	 = primary_overlay_format1,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 3,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay_2",
>> +		.id				= OVERLAY_PLANE_2,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
>> +		.formats	 = primary_overlay_format1,
>> +		.num_modifiers = ARRAY_SIZE(format_modifier0),
>> +		.modifiers	 = format_modifier0,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = DRM_MODE_ROTATE_0 |
>> +					   DRM_MODE_ROTATE_90 |
>> +					   DRM_MODE_ROTATE_180 |
>> +					   DRM_MODE_ROTATE_270 |
>> +					   DRM_MODE_REFLECT_X |
>> +					   DRM_MODE_REFLECT_Y,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = FRAC_16_16(1, 3),
>> +		.max_scale	 = FRAC_16_16(10, 1),
>> +		.zpos		 = 4,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Overlay_3",
>> +		.id				= OVERLAY_PLANE_3,
>> +		.type		 = DRM_PLANE_TYPE_OVERLAY,
>> +		.num_formats = ARRAY_SIZE(primary_overlay_format1),
>> +		.formats	 = primary_overlay_format1,
>> +		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
>> +		.modifiers	 = secondary_format_modifiers,
>> +		.min_width	 = 0,
>> +		.min_height  = 0,
>> +		.max_width	 = 4096,
>> +		.max_height  = 4096,
>> +		.rotation	 = 0,
>> +		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> +					   BIT(DRM_MODE_BLEND_PREMULTI) |
>> +					   BIT(DRM_MODE_BLEND_COVERAGE),
>> +		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> +						  BIT(DRM_COLOR_YCBCR_BT2020),
>> +		.degamma_size	= DEGAMMA_SIZE,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 5,
>> +		.watermark	 = true,
>> +		.color_mgmt  = true,
>> +		.roi		 = true,
>> +		},
>> +		{
>> +		.name		 = "Cursor",
>> +		.id				= CURSOR_PLANE_0,
>> +		.type		 = DRM_PLANE_TYPE_CURSOR,
>> +		.num_formats = ARRAY_SIZE(cursor_formats),
>> +		.formats	 = cursor_formats,
>> +		.num_modifiers = 0,
>> +		.modifiers	 = NULL,
>> +		.min_width	 = 32,
>> +		.min_height  = 32,
>> +		.max_width	 = 64,
>> +		.max_height  = 64,
>> +		.rotation	 = 0,
>> +		.degamma_size = 0,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 255,
>> +		.watermark	 = false,
>> +		.color_mgmt  = false,
>> +		.roi		 = false,
>> +		},
>> +		{
>> +		.name		 = "Cursor_1",
>> +		.id				= CURSOR_PLANE_1,
>> +		.type		 = DRM_PLANE_TYPE_CURSOR,
>> +		.num_formats = ARRAY_SIZE(cursor_formats),
>> +		.formats	 = cursor_formats,
>> +		.num_modifiers = 0,
>> +		.modifiers	 = NULL,
>> +		.min_width	 = 32,
>> +		.min_height  = 32,
>> +		.max_width	 = 64,
>> +		.max_height  = 64,
>> +		.rotation	 = 0,
>> +		.degamma_size = 0,
>> +		.min_scale	 = DRM_PLANE_NO_SCALING,
>> +		.max_scale	 = DRM_PLANE_NO_SCALING,
>> +		.zpos		 = 255,
>> +		.watermark	 = false,
>> +		.color_mgmt  = false,
>> +		.roi		 = false,
>> +		},
>> +	},
>> +};
>> +
>> +static const struct vs_dc_info dc_info[] = {
> 
> Again, please split into per-generation instances.
> 
>> +	{
>> +		/* DC_REV_0 */
>> +		.name			= "DC8200",
>> +		.panel_num		= 2,
>> +		.plane_num		= 8,
>> +		.planes			= dc_hw_planes[DC_REV_0],
>> +		.layer_num		= 6,
>> +		.max_bpc		= 10,
>> +		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
>> +						  DRM_COLOR_FORMAT_YCBCR444 |
>> +						  DRM_COLOR_FORMAT_YCBCR422 |
>> +						  DRM_COLOR_FORMAT_YCBCR420,
>> +		.gamma_size		= GAMMA_EX_SIZE,
>> +		.gamma_bits		= 12,
>> +		.pitch_alignment	= 128,
>> +		.pipe_sync		= false,
>> +		.background		= true,
>> +		.panel_sync		= true,
>> +		.cap_dec		= true,
>> +	},
>> +	{
>> +		/* DC_REV_1 */
>> +		.name			= "DC8200",
>> +		.panel_num		= 2,
>> +		.plane_num		= 6,
>> +		.planes			= dc_hw_planes[DC_REV_1],
>> +		.layer_num		= 4,
>> +		.max_bpc		= 10,
>> +		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
>> +						  DRM_COLOR_FORMAT_YCBCR444 |
>> +						  DRM_COLOR_FORMAT_YCBCR422 |
>> +						  DRM_COLOR_FORMAT_YCBCR420,
>> +		.gamma_size		= GAMMA_EX_SIZE,
>> +		.gamma_bits		= 12,
>> +		.pitch_alignment	= 128,
>> +		.pipe_sync		= false,
>> +		.background		= true,
>> +		.panel_sync		= true,
>> +		.cap_dec		= true,
>> +	},
>> +	{
>> +		/* DC_REV_2 */
>> +		.name			= "DC8200",
>> +		.panel_num		= 2,
>> +		.plane_num		= 8,
>> +		.planes			= dc_hw_planes[DC_REV_2],
>> +		.layer_num		= 6,
>> +		.max_bpc		= 10,
>> +		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
>> +						  DRM_COLOR_FORMAT_YCBCR444 |
>> +						  DRM_COLOR_FORMAT_YCBCR422 |
>> +						  DRM_COLOR_FORMAT_YCBCR420,
>> +		.gamma_size		= GAMMA_EX_SIZE,
>> +		.gamma_bits		= 12,
>> +		.pitch_alignment	= 128,
>> +		.pipe_sync		= false,
>> +		.background		= true,
>> +		.panel_sync		= true,
>> +		.cap_dec		= false,
>> +	},
>> +};
>> +
>> +static const struct dc_hw_funcs hw_func;
>> +
>> +static inline u32 hi_read(struct dc_hw *hw, u32 reg)
>> +{
>> +	return readl(hw->hi_base + reg);
>> +}
>> +
>> +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
>> +{
>> +	writel(value, hw->hi_base + reg);
>> +}
>> +
>> +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
>> +{
>> +	writel(value, hw->reg_base + reg - DC_REG_BASE);
>> +}
>> +
>> +static inline u32 dc_read(struct dc_hw *hw, u32 reg)
>> +{
>> +	u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
>> +
>> +	return value;
>> +}
>> +
>> +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
>> +{
>> +	u32 value = dc_read(hw, reg);
>> +
>> +	value &= ~clear;
>> +	value |= set;
>> +	dc_write(hw, reg, value);
>> +}
>> +
>> +static void load_default_filter(struct dc_hw *hw,
>> +				const struct dc_hw_plane_reg *reg, u32 offset)
>> +{
>> +	u8 i;
>> +
>> +	dc_write(hw, reg->scale_config + offset, 0x33);
>> +	dc_write(hw, reg->init_offset + offset, 0x80008000);
>> +	dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
>> +	for (i = 0; i < H_COEF_SIZE; i++)
>> +		dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
>> +
>> +	dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
>> +	for (i = 0; i < V_COEF_SIZE; i++)
>> +		dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
>> +}
>> +
>> +static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
>> +			    u32 offset, u16 *table)
>> +{
>> +	dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
>> +	dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
>> +	dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
>> +	dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
>> +	dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
>> +}
>> +
>> +static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
>> +			    u32 offset, s32 *table)
>> +{
>> +	dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
>> +		 (0xFFFF & table[0]) | (table[1] << 16));
>> +	dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
>> +		 (0xFFFF & table[2]) | (table[3] << 16));
>> +	dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
>> +		 (0xFFFF & table[4]) | (table[5] << 16));
>> +	dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
>> +		 (0xFFFF & table[6]) | (table[7] << 16));
>> +	dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
>> +	dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
>> +	dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
>> +	dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
>> +	dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
>> +	dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
>> +}
>> +
>> +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
>> +{
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
>> +		 table[0] | (table[1] << 16));
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
>> +		 table[2] | (table[3] << 16));
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
>> +		 table[4] | (table[5] << 16));
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
>> +		 table[6] | (table[7] << 16));
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
>> +	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
>> +}
>> +
>> +static bool is_rgb(enum dc_hw_color_format format)
>> +{
>> +	switch (format) {
>> +	case FORMAT_X4R4G4B4:
>> +	case FORMAT_A4R4G4B4:
>> +	case FORMAT_X1R5G5B5:
>> +	case FORMAT_A1R5G5B5:
>> +	case FORMAT_R5G6B5:
>> +	case FORMAT_X8R8G8B8:
>> +	case FORMAT_A8R8G8B8:
>> +	case FORMAT_A2R10G10B10:
>> +		return true;
>> +	default:
>> +		return false;
>> +	}
>> +}
>> +
>> +static void load_degamma_table(struct dc_hw *hw,
>> +			       const struct dc_hw_plane_reg *reg,
>> +			       u32 offset, u16 *table)
>> +{
>> +	u16 i;
>> +	u32 value;
>> +
>> +	dc_write(hw, reg->degamma_index + offset, 0);
>> +
>> +	for (i = 0; i < DEGAMMA_SIZE; i++) {
>> +		value = table[i] | (table[i] << 16);
>> +		dc_write(hw, reg->degamma_data + offset, value);
>> +		dc_write(hw, reg->degamma_ex_data + offset, table[i]);
>> +	}
>> +}
>> +
>> +static u32 get_addr_offset(u32 id)
>> +{
>> +	u32 offset = 0;
>> +
>> +	switch (id) {
>> +	case PRIMARY_PLANE_1:
>> +	case OVERLAY_PLANE_1:
>> +		offset = 0x04;
>> +		break;
>> +	case OVERLAY_PLANE_2:
>> +		offset = 0x08;
>> +		break;
>> +	case OVERLAY_PLANE_3:
>> +		offset = 0x0C;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return offset;
>> +}
>> +
>> +int dc_hw_init(struct dc_hw *hw)
>> +{
>> +	u8 i, id, panel_num, layer_num;
>> +	u32 offset;
>> +	u32 revision = hi_read(hw, DC_HW_REVISION);
>> +	u32 cid = hi_read(hw, DC_HW_CHIP_CID);
>> +	const struct dc_hw_plane_reg *reg;
>> +
>> +	switch (revision) {
>> +	case 0x5720:
>> +		hw->rev = DC_REV_0;
>> +		break;
>> +	case 0x5721:
>> +		switch (cid) {
>> +		case 0x30B:
>> +			hw->rev = DC_REV_1;
>> +			break;
>> +		case 0x310:
>> +			hw->rev = DC_REV_2;
>> +			break;
>> +		default:
>> +			hw->rev = DC_REV_0;
>> +			break;
>> +		}
>> +		break;
>> +	default:
>> +		return -ENXIO;
>> +	}
> 
> We (drm/msm) had code like this for a while (and autodetection of the HW 
> ID). And nowadays we are migrating to of_device_get_match_data and 
> per-SoC compat names. It is just easier to handle, it allows one to 
> specify device more precisely and also it simplifies DT schema.
> 
>> +
>> +	hw->info = (struct vs_dc_info *)&dc_info[hw->rev];
>> +	hw->func = (struct dc_hw_funcs *)&hw_func;
>> +
>> +	layer_num = hw->info->layer_num;
>> +	for (i = 0; i < layer_num; i++) {
>> +		id = hw->info->planes[i].id;
>> +		offset = get_addr_offset(id);
>> +		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
>> +			reg = &dc_plane_reg[0];
>> +		else
>> +			reg = &dc_plane_reg[1];
>> +
>> +		load_default_filter(hw, reg, offset);
>> +		load_rgb_to_rgb(hw, reg, offset, RGB2RGB);
>> +	}
>> +
>> +	panel_num = hw->info->panel_num;
>> +	for (i = 0; i < panel_num; i++) {
>> +		offset = i << 2;
>> +
>> +		load_rgb_to_yuv(hw, offset, RGB2YUV);
>> +		dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
>> +
>> +		offset = i ? DC_CURSOR_OFFSET : 0;
>> +		dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
>> +		dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +void dc_hw_deinit(struct dc_hw *hw)
>> +{
>> +	/* Nothing to do */
>> +}
>> +
>> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
>> +			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
>> +			struct dc_hw_position *pos, struct dc_hw_blend *blend)
>> +{
>> +	struct dc_hw_plane *plane = &hw->plane[id];
>> +
>> +	if (plane) {
>> +		if (fb) {
>> +			if (!fb->enable)
>> +				plane->fb.enable = false;
>> +			else
>> +				memcpy(&plane->fb, fb,
>> +				       sizeof(*fb) - sizeof(fb->dirty));
>> +			plane->fb.dirty = true;
>> +		}
>> +		if (scale) {
>> +			memcpy(&plane->scale, scale,
>> +			       sizeof(*scale) - sizeof(scale->dirty));
>> +			plane->scale.dirty = true;
>> +		}
>> +		if (pos) {
>> +			memcpy(&plane->pos, pos,
>> +			       sizeof(*pos) - sizeof(pos->dirty));
>> +			plane->pos.dirty = true;
>> +		}
>> +		if (blend) {
>> +			memcpy(&plane->blend, blend,
>> +			       sizeof(*blend) - sizeof(blend->dirty));
>> +			plane->blend.dirty = true;
>> +		}
>> +	}
>> +}
>> +
>> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode)
>> +{
>> +	struct dc_hw_plane *plane = &hw->plane[id];
>> +
>> +	if (plane) {
>> +		if (hw->info->planes[id].degamma_size) {
>> +			plane->degamma.mode = mode;
>> +			plane->degamma.dirty = true;
>> +		} else {
>> +			plane->degamma.dirty = false;
>> +		}
>> +	}
>> +}
>> +
>> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi)
>> +{
>> +	struct dc_hw_plane *plane = &hw->plane[id];
>> +
>> +	if (plane) {
>> +		memcpy(&plane->roi, roi, sizeof(*roi) - sizeof(roi->dirty));
>> +		plane->roi.dirty = true;
>> +	}
>> +}
>> +
>> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
>> +			   struct dc_hw_colorkey *colorkey)
>> +{
>> +	struct dc_hw_plane *plane = &hw->plane[id];
>> +
>> +	if (plane) {
>> +		memcpy(&plane->colorkey, colorkey,
>> +		       sizeof(*colorkey) - sizeof(colorkey->dirty));
>> +		plane->colorkey.dirty = true;
>> +	}
>> +}
>> +
>> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos)
>> +{
>> +	memcpy(&hw->qos, qos, sizeof(*qos) - sizeof(qos->dirty));
>> +	hw->qos.dirty = true;
>> +}
>> +
>> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor)
>> +{
>> +	memcpy(&hw->cursor[id], cursor, sizeof(*cursor) - sizeof(cursor->dirty));
>> +	hw->cursor[id].dirty = true;
>> +}
>> +
>> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
>> +			u16 r, u16 g, u16 b)
>> +{
>> +	if (index >= hw->info->gamma_size)
>> +		return;
>> +
>> +	hw->gamma[id].gamma[index][0] = r;
>> +	hw->gamma[id].gamma[index][1] = g;
>> +	hw->gamma[id].gamma[index][2] = b;
>> +	hw->gamma[id].dirty = true;
>> +}
>> +
>> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
>> +{
>> +	hw->gamma[id].enable = enable;
>> +	hw->gamma[id].dirty = true;
>> +}
>> +
>> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display)
>> +{
>> +	u8 id = display->id;
>> +
>> +	memcpy(&hw->display[id], display, sizeof(*display));
>> +
>> +	hw->func->display(hw, display);
>> +}
>> +
>> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable)
>> +{
>> +	if (enable)
>> +		hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
>> +	else
>> +		hi_write(hw, AQ_INTR_ENBL, 0);
>> +}
>> +
>> +u32 dc_hw_get_interrupt(struct dc_hw *hw)
>> +{
>> +	return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
>> +}
>> +
>> +bool dc_hw_check_underflow(struct dc_hw *hw)
>> +{
>> +	return dc_read(hw, DC_FRAMEBUFFER_CONFIG) & BIT(5);
>> +}
>> +
>> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable)
>> +{
>> +	u32 i, offset;
>> +	u8 id, layer_num = hw->info->layer_num;
>> +	u8 panel_num = hw->info->panel_num;
>> +
>> +	for (i = 0; i < layer_num; i++) {
>> +		id = hw->info->planes[i].id;
>> +		offset = get_addr_offset(id);
>> +		if (enable) {
>> +			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
>> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, BIT(12), 0);
>> +			else
>> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, BIT(31), 0);
>> +		} else {
>> +			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
>> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, 0, BIT(12));
>> +			else
>> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, 0, BIT(31));
>> +		}
>> +	}
>> +
>> +	for (i = 0; i < panel_num; i++) {
>> +		offset = i << 2;
>> +		if (enable)
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, BIT(0));
>> +		else
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, BIT(0), 0);
>> +	}
>> +}
>> +
>> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
>> +{
>> +	if (out <= OUT_DP)
>> +		hw->out[id] = out;
>> +}
>> +
>> +static void gamma_ex_commit(struct dc_hw *hw)
>> +{
>> +	u8 panel_num = hw->info->panel_num;
>> +	u16 i, j;
>> +	u32 value;
>> +
>> +	for (j = 0; j < panel_num; j++) {
>> +		if (hw->gamma[j].dirty) {
>> +			if (hw->gamma[j].enable) {
>> +				dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (j << 2), 0x00);
>> +				for (i = 0; i < GAMMA_EX_SIZE; i++) {
>> +					value = hw->gamma[j].gamma[i][2] |
>> +						(hw->gamma[j].gamma[i][1] << 12);
>> +					dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (j << 2), value);
>> +					dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (j << 2),
>> +						 hw->gamma[j].gamma[i][0]);
>> +				}
>> +				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
>> +					     BIT(13), 0);
>> +			} else {
>> +				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
>> +					     0, BIT(13));
>> +			}
>> +			hw->gamma[j].dirty = false;
>> +		}
>> +	}
>> +}
>> +
>> +static void plane_commit(struct dc_hw *hw)
>> +{
>> +	struct dc_hw_plane *plane;
>> +	const struct dc_hw_plane_reg *reg;
>> +	bool primary = false;
>> +	u8 id, layer_num = hw->info->layer_num;
>> +	u32 i, offset;
>> +
>> +	for (i = 0; i < layer_num; i++) {
>> +		plane = &hw->plane[i];
>> +		id = hw->info->planes[i].id;
>> +		offset = get_addr_offset(id);
>> +		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
>> +			reg = &dc_plane_reg[0];
>> +			primary = true;
>> +		} else {
>> +			reg = &dc_plane_reg[1];
>> +			primary = false;
>> +		}
> 
> Can you please move register defines to some internal hw_plane 
> structure. These details are known at the time of creation of the plane. 
> There is no need to determine them again and again.
> 
>> +
>> +		if (plane->fb.dirty) {
>> +			if (plane->fb.enable) {
> 
> if (plane->fb.dirty && plane->fb.enable) will save you one level of 
> indentation.
> 
> However it might be better to use existing DRM flags instead of 
> inventing your own flags.
> 
>> +				dc_write(hw, reg->y_address + offset,
>> +					 plane->fb.y_address);
>> +				dc_write(hw, reg->u_address + offset,
>> +					 plane->fb.u_address);
>> +				dc_write(hw, reg->v_address + offset,
>> +					 plane->fb.v_address);
>> +				dc_write(hw, reg->y_stride + offset,
>> +					 plane->fb.y_stride);
>> +				dc_write(hw, reg->u_stride + offset,
>> +					 plane->fb.u_stride);
>> +				dc_write(hw, reg->v_stride + offset,
>> +					 plane->fb.v_stride);
>> +				dc_write(hw, reg->size + offset,
>> +					 plane->fb.width |
>> +					 (plane->fb.height << 15));
>> +				dc_write(hw, reg->water_mark + offset,
>> +					 plane->fb.water_mark);
>> +
>> +				if (plane->fb.clear_enable)
>> +					dc_write(hw, reg->clear_value + offset,
>> +						 plane->fb.clear_value);
>> +			}
>> +
>> +			if (primary) {
> 
> You have two kinds of planes. Primary and overlays. Could you please 
> split this code into two separate functions and define two vtables, one 
> for primary planes and one for overlays. There is no need to stick 
> everything into a single funcion that handles everything.
> 
>> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
>> +					     (plane->fb.format << 26) |
>> +					     (plane->fb.uv_swizzle << 25) |
>> +					     (plane->fb.swizzle << 23) |
>> +					     (plane->fb.tile_mode << 17) |
>> +					     (plane->fb.yuv_color_space << 14) |
>> +					     (plane->fb.rotation << 11) |
>> +					     (plane->fb.clear_enable << 8),
>> +					     (0x1F << 26) |
>> +					     BIT(25) |
>> +					     (0x03 << 23) |
>> +					     (0x1F << 17) |
>> +					     (0x07 << 14) |
>> +					     (0x07 << 11) |
>> +					     BIT(8));
>> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +					     (plane->fb.dec_enable << 1) |
>> +					     (plane->fb.enable << 13) |
>> +					     (plane->fb.zpos << 16) |
>> +					     (plane->fb.display_id << 19),
>> +					     BIT(1) | BIT(13) | (0x07 << 16) | BIT(19));
> 
> It looks like this code can enjoy defining names for all the magic 
> values. Otherwise it is impossible to support it.
> 
>> +			} else {
>> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> +					     (plane->fb.dec_enable << 27) |
>> +					     (plane->fb.clear_enable << 25) |
>> +					     (plane->fb.enable << 24) |
>> +					     (plane->fb.format << 16) |
>> +					     (plane->fb.uv_swizzle << 15) |
>> +					     (plane->fb.swizzle << 13) |
>> +					     (plane->fb.tile_mode << 8) |
>> +					     (plane->fb.yuv_color_space << 5) |
>> +					     (plane->fb.rotation << 2),
>> +					     BIT(27) |
>> +					     BIT(25) |
>> +					     BIT(24) |
>> +					     (0x1F << 16) |
>> +					     BIT(15) |
>> +					     (0x03 << 13) |
>> +					     (0x1F << 8) |
>> +					     (0x07 << 5) |
>> +					     (0x07 << 2));
>> +				dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
>> +					     plane->fb.zpos | (plane->fb.display_id << 3),
>> +					     0x07 | BIT(3));
>> +			}
>> +			plane->fb.dirty = false;
>> +		}
>> +
>> +		if (plane->scale.dirty) {
>> +			if (plane->scale.enable) {
>> +				dc_write(hw, reg->scale_factor_x + offset,
>> +					 plane->scale.scale_factor_x);
>> +				dc_write(hw, reg->scale_factor_y + offset,
>> +					 plane->scale.scale_factor_y);
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG + offset,
>> +						     BIT(22), 0);
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_SCALE_CONFIG + offset,
>> +						     BIT(8), 0);
>> +			} else {
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG + offset,
>> +						     0, BIT(22));
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_SCALE_CONFIG + offset,
>> +						     0, BIT(8));
>> +			}
>> +			plane->scale.dirty = false;
>> +		}
>> +
>> +		if (plane->pos.dirty) {
>> +			dc_write(hw, reg->top_left + offset,
>> +				 plane->pos.start_x |
>> +				 (plane->pos.start_y << 15));
>> +			dc_write(hw, reg->bottom_right + offset,
>> +				 plane->pos.end_x |
>> +				 (plane->pos.end_y << 15));
>> +			plane->pos.dirty = false;
>> +		}
>> +
>> +		if (plane->blend.dirty) {
>> +			dc_write(hw, reg->src_global_color + offset,
>> +				 plane->blend.alpha << 24);
>> +			dc_write(hw, reg->dst_global_color + offset,
>> +				 plane->blend.alpha << 24);
>> +			switch (plane->blend.blend_mode) {
>> +			case BLEND_PREMULTI:
>> +				dc_write(hw, reg->blend_config + offset, 0x3450);
>> +				break;
>> +			case BLEND_COVERAGE:
>> +				dc_write(hw, reg->blend_config + offset, 0x3950);
>> +				break;
>> +			case BLEND_PIXEL_NONE:
>> +				dc_write(hw, reg->blend_config + offset, 0x3548);
>> +				break;
>> +			default:
>> +				break;
>> +			}
>> +			plane->blend.dirty = false;
>> +		}
>> +
>> +		if (plane->colorkey.dirty) {
>> +			dc_write(hw, reg->color_key + offset, plane->colorkey.colorkey);
>> +			dc_write(hw, reg->color_key_high + offset,
>> +				 plane->colorkey.colorkey_high);
>> +
>> +			if (primary)
>> +				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
>> +					     plane->colorkey.transparency << 9, 0x03 << 9);
>> +			else
>> +				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> +					     plane->colorkey.transparency, 0x03);
>> +
>> +			plane->colorkey.dirty = false;
>> +		}
>> +
>> +		if (plane->roi.dirty) {
>> +			if (plane->roi.enable) {
>> +				dc_write(hw, reg->roi_origin + offset,
>> +					 plane->roi.x | (plane->roi.y << 16));
>> +				dc_write(hw, reg->roi_size + offset,
>> +					 plane->roi.width | (plane->roi.height << 16));
>> +				if (primary)
>> +					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     BIT(0), 0);
>> +				else
>> +					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> +						     BIT(22), 0);
>> +			} else {
>> +				if (primary)
>> +					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     0, BIT(0));
>> +				else
>> +					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> +						     0, BIT(22));
>> +			}
>> +			plane->roi.dirty = false;
>> +		}
>> +	}
>> +}
>> +
>> +static void plane_ex_commit(struct dc_hw *hw)
>> +{
>> +	struct dc_hw_plane *plane;
>> +	const struct dc_hw_plane_reg *reg;
>> +	bool primary = false;
>> +	u8 id, layer_num = hw->info->layer_num;
>> +	u32 i, offset;
>> +
>> +	for (i = 0; i < layer_num; i++) {
>> +		plane = &hw->plane[i];
>> +		id = hw->info->planes[i].id;
>> +		offset = get_addr_offset(id);
>> +		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
>> +			reg = &dc_plane_reg[0];
>> +			primary = true;
>> +		} else {
>> +			reg = &dc_plane_reg[1];
>> +			primary = false;
>> +		}
>> +
>> +		if (plane->fb.dirty) {
>> +			if (is_rgb(plane->fb.format)) {
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     BIT(6), BIT(8));
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_CONFIG + offset,
>> +						     BIT(29), BIT(30));
>> +			} else {
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     BIT(8), BIT(6));
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_CONFIG + offset,
>> +						     BIT(30), BIT(29));
>> +				switch (plane->fb.yuv_color_space) {
>> +				case COLOR_SPACE_601:
>> +					load_yuv_to_rgb(hw, reg, offset, YUV601_2RGB);
>> +					break;
>> +				case COLOR_SPACE_709:
>> +					load_yuv_to_rgb(hw, reg, offset, YUV709_2RGB);
>> +					break;
>> +				case COLOR_SPACE_2020:
>> +					load_yuv_to_rgb(hw, reg, offset, YUV2020_2RGB);
>> +					break;
>> +				default:
>> +					break;
>> +				}
>> +			}
>> +		}
>> +		if (plane->degamma.dirty) {
>> +			switch (plane->degamma.mode) {
>> +			case VS_DEGAMMA_DISABLE:
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     0, BIT(5));
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_CONFIG + offset,
>> +						     0, BIT(28));
>> +				break;
>> +			case VS_DEGAMMA_BT709:
>> +				load_degamma_table(hw, reg, offset, DEGAMMA_709);
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     BIT(5), 0);
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_CONFIG + offset,
>> +						     BIT(28), 0);
>> +				break;
>> +			case VS_DEGAMMA_BT2020:
>> +				load_degamma_table(hw, reg, offset, DEGAMMA_2020);
>> +				if (primary)
>> +					dc_set_clear(hw,
>> +						     DC_FRAMEBUFFER_CONFIG_EX + offset,
>> +						     BIT(5), 0);
>> +				else
>> +					dc_set_clear(hw,
>> +						     DC_OVERLAY_CONFIG + offset,
>> +						     BIT(28), 0);
>> +				break;
>> +			default:
>> +				break;
>> +			}
>> +			plane->degamma.dirty = false;
>> +		}
>> +	}
>> +	plane_commit(hw);
>> +}
>> +
>> +static void setup_display(struct dc_hw *hw, struct dc_hw_display *display)
>> +{
>> +	u8 id = display->id;
>> +	u32 dpi_cfg, offset = id << 2;
>> +
>> +	if (hw->display[id].enable) {
>> +		switch (display->bus_format) {
>> +		case MEDIA_BUS_FMT_RGB565_1X16:
>> +			dpi_cfg = 0;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB666_1X18:
>> +			dpi_cfg = 3;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
>> +			dpi_cfg = 4;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB888_1X24:
>> +			dpi_cfg = 5;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB101010_1X30:
>> +			dpi_cfg = 6;
>> +			break;
>> +		default:
>> +			dpi_cfg = 5;
>> +			break;
>> +		}
>> +		dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
>> +
>> +		if (id == 0)
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
>> +		else
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
>> +
>> +		dc_write(hw, DC_DISPLAY_H + offset, hw->display[id].h_active |
>> +			 (hw->display[id].h_total << 16));
>> +		dc_write(hw, DC_DISPLAY_H_SYNC + offset,
>> +			 hw->display[id].h_sync_start |
>> +			 (hw->display[id].h_sync_end << 15) |
>> +			 (hw->display[id].h_sync_polarity ? 0 : BIT(31)) |
>> +			 BIT(30));
>> +		dc_write(hw, DC_DISPLAY_V + offset, hw->display[id].v_active |
>> +				(hw->display[id].v_total << 16));
>> +		dc_write(hw, DC_DISPLAY_V_SYNC + offset,
>> +			 hw->display[id].v_sync_start |
>> +			 (hw->display[id].v_sync_end << 15) |
>> +			 (hw->display[id].v_sync_polarity ? 0 : BIT(31)) |
>> +			 BIT(30));
>> +
>> +		if (hw->info->pipe_sync)
>> +			dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
>> +				     0, BIT(3) | BIT(4));
>> +
>> +		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(12), 0);
>> +		if (id == 0)
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(0), BIT(3));
>> +		else
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(1), BIT(3));
>> +	} else {
>> +		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(12));
>> +		if (id == 0)
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
>> +		else
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
>> +	}
>> +}
>> +
>> +static void setup_display_ex(struct dc_hw *hw, struct dc_hw_display *display)
>> +{
>> +	u8 id = display->id;
>> +	u32 dp_cfg, offset = id << 2;
>> +	bool is_yuv = false;
>> +
>> +	if (hw->display[id].enable && hw->out[id] == OUT_DP) {
>> +		switch (display->bus_format) {
>> +		case MEDIA_BUS_FMT_RGB565_1X16:
>> +			dp_cfg = 0;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB666_1X18:
>> +			dp_cfg = 1;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB888_1X24:
>> +			dp_cfg = 2;
>> +			break;
>> +		case MEDIA_BUS_FMT_RGB101010_1X30:
>> +			dp_cfg = 3;
>> +			break;
>> +		case MEDIA_BUS_FMT_UYVY8_1X16:
>> +			dp_cfg = 2 << 4;
>> +			is_yuv = true;
>> +			break;
>> +		case MEDIA_BUS_FMT_YUV8_1X24:
>> +			dp_cfg = 4 << 4;
>> +			is_yuv = true;
>> +			break;
>> +		case MEDIA_BUS_FMT_UYVY10_1X20:
>> +			dp_cfg = 8 << 4;
>> +			is_yuv = true;
>> +			break;
>> +		case MEDIA_BUS_FMT_YUV10_1X30:
>> +			dp_cfg = 10 << 4;
>> +			is_yuv = true;
>> +			break;
>> +		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
>> +			dp_cfg = 12 << 4;
>> +			is_yuv = true;
>> +			break;
>> +		case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
>> +			dp_cfg = 13 << 4;
>> +			is_yuv = true;
>> +			break;
>> +		default:
>> +			dp_cfg = 2;
>> +			break;
>> +		}
>> +		if (is_yuv)
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(16), 0);
>> +		else
>> +			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(16));
>> +		dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | BIT(3));
>> +	}
>> +
>> +	if (hw->out[id] == OUT_DPI)
>> +		dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, BIT(3));
>> +
>> +	setup_display(hw, display);
>> +}
>> +
>> +static const struct dc_hw_funcs hw_func = {
>> +	.gamma = &gamma_ex_commit,
>> +	.plane = &plane_ex_commit,
>> +	.display = setup_display_ex,
>> +};
>> +
>> +void dc_hw_commit(struct dc_hw *hw)
>> +{
>> +	u32 i, offset = 0;
>> +	u8 plane_num = hw->info->plane_num;
>> +	u8 layer_num = hw->info->layer_num;
>> +	u8 cursor_num = plane_num - layer_num;
>> +
>> +	hw->func->gamma(hw);
>> +	hw->func->plane(hw);
>> +
>> +	for (i = 0; i < cursor_num; i++) {
>> +		if (hw->cursor[i].dirty) {
>> +			offset = hw->cursor[i].display_id ? DC_CURSOR_OFFSET : 0;
>> +			if (hw->cursor[i].enable) {
>> +				dc_write(hw, DC_CURSOR_ADDRESS + offset,
>> +					 hw->cursor[i].address);
>> +				dc_write(hw, DC_CURSOR_LOCATION + offset, hw->cursor[i].x |
>> +					 (hw->cursor[i].y << 16));
>> +				dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
>> +					     (hw->cursor[i].hot_x << 16) |
>> +					     (hw->cursor[i].hot_y << 8) |
>> +					     (hw->cursor[i].size << 5) |
>> +					     BIT(3) | BIT(2) | 0x02,
>> +					     (0xFF << 16) |
>> +					     (0xFF << 8) |
>> +					     (0x07 << 5) | 0x1F);
>> +			} else {
>> +				dc_set_clear(hw, DC_CURSOR_CONFIG + offset, BIT(3), 0x03);
>> +			}
>> +			hw->cursor[i].dirty = false;
>> +		}
>> +	}
>> +
>> +	if (hw->qos.dirty) {
>> +		dc_set_clear(hw, DC_QOS_CONFIG, (hw->qos.high_value << 4) |
>> +					 hw->qos.low_value, 0xFF);
>> +		hw->qos.dirty = false;
>> +	}
>> +}
>> +
>> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
>> new file mode 100644
>> index 000000000..9a1d767ae
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
>> @@ -0,0 +1,492 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_DC_HW_H__
>> +#define __VS_DC_HW_H__
>> +
>> +#define AQ_INTR_ACKNOWLEDGE				0x0010
>> +#define AQ_INTR_ENBL					0x0014
> 
> Please take care to align all the defines.
> 
>> +#define DC_HW_REVISION					0x0024
>> +#define DC_HW_CHIP_CID					0x0030
>> +
>> +#define DC_REG_BASE						0x0800
>> +#define DC_REG_RANGE					0x2000
>> +#define DC_SEC_REG_OFFSET				0x100000
>> +
>> +#define DC_FRAMEBUFFER_CONFIG			0x1518
>> +#define DC_FRAMEBUFFER_CONFIG_EX		0x1CC0
>> +#define DC_FRAMEBUFFER_SCALE_CONFIG		0x1520
>> +#define DC_FRAMEBUFFER_TOP_LEFT			0x24D8
>> +#define DC_FRAMEBUFFER_BOTTOM_RIGHT		0x24E0
>> +#define DC_FRAMEBUFFER_ADDRESS			0x1400
>> +#define DC_FRAMEBUFFER_U_ADDRESS		0x1530
>> +#define DC_FRAMEBUFFER_V_ADDRESS		0x1538
>> +#define DC_FRAMEBUFFER_STRIDE			0x1408
>> +#define DC_FRAMEBUFFER_U_STRIDE			0x1800
>> +#define DC_FRAMEBUFFER_V_STRIDE			0x1808
>> +#define DC_FRAMEBUFFER_SIZE				0x1810
>> +#define DC_FRAMEBUFFER_SCALE_FACTOR_X		0x1828
>> +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y		0x1830
>> +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX	0x1838
>> +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA	0x1A00
>> +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX	0x1A08
>> +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA	0x1A10
>> +#define DC_FRAMEBUFFER_INIT_OFFSET			0x1A20
>> +#define DC_FRAMEBUFFER_COLOR_KEY			0x1508
>> +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH		0x1510
>> +#define DC_FRAMEBUFFER_CLEAR_VALUE			0x1A18
>> +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX	0x1818
>> +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA		0x1820
>> +#define DC_FRAMEBUFFER_BG_COLOR				0x1528
>> +#define DC_FRAMEBUFFER_ROI_ORIGIN			0x1CB0
>> +#define DC_FRAMEBUFFER_ROI_SIZE				0x1CB8
>> +#define DC_FRAMEBUFFER_WATER_MARK			0x1CE8
>> +#define DC_FRAMEBUFFER_DEGAMMA_INDEX		0x1D88
>> +#define DC_FRAMEBUFFER_DEGAMMA_DATA			0x1D90
>> +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA		0x1D98
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEF0		0x1DA0
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEF1		0x1DA8
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEF2		0x1DB0
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEF3		0x1DB8
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEF4		0x1E00
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0		0x1E08
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1		0x1E10
>> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2		0x1E18
>> +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND		0x1E88
>> +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND		0x1E90
>> +#define DC_FRAMEBUFFER_RGBTORGB_COEF0		0x1E20
>> +#define DC_FRAMEBUFFER_RGBTORGB_COEF1		0x1E28
>> +#define DC_FRAMEBUFFER_RGBTORGB_COEF2		0x1E30
>> +#define DC_FRAMEBUFFER_RGBTORGB_COEF3		0x1E38
>> +#define DC_FRAMEBUFFER_RGBTORGB_COEF4		0x1E40
>> +#define DC_FRAMEBUFFER_BLEND_CONFIG			0x2510
>> +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR		0x2500
>> +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR		0x2508
>> +
>> +#define DC_OVERLAY_CONFIG					0x1540
>> +#define DC_OVERLAY_CONFIG_EX				0x2540
>> +#define DC_OVERLAY_SCALE_CONFIG				0x1C00
>> +#define DC_OVERLAY_BLEND_CONFIG				0x1580
>> +#define DC_OVERLAY_TOP_LEFT					0x1640
>> +#define DC_OVERLAY_BOTTOM_RIGHT				0x1680
>> +#define DC_OVERLAY_ADDRESS					0x15C0
>> +#define DC_OVERLAY_U_ADDRESS				0x1840
>> +#define DC_OVERLAY_V_ADDRESS				0x1880
>> +#define DC_OVERLAY_STRIDE					0x1600
>> +#define DC_OVERLAY_U_STRIDE					0x18C0
>> +#define DC_OVERLAY_V_STRIDE					0x1900
>> +#define DC_OVERLAY_SIZE						0x17C0
>> +#define DC_OVERLAY_SCALE_FACTOR_X			0x1A40
>> +#define DC_OVERLAY_SCALE_FACTOR_Y			0x1A80
>> +#define DC_OVERLAY_H_FILTER_COEF_INDEX		0x1AC0
>> +#define DC_OVERLAY_H_FILTER_COEF_DATA		0x1B00
>> +#define DC_OVERLAY_V_FILTER_COEF_INDEX		0x1B40
>> +#define DC_OVERLAY_V_FILTER_COEF_DATA		0x1B80
>> +#define DC_OVERLAY_INIT_OFFSET				0x1BC0
>> +#define DC_OVERLAY_COLOR_KEY				0x1740
>> +#define DC_OVERLAY_COLOR_KEY_HIGH			0x1780
>> +#define DC_OVERLAY_CLEAR_VALUE				0x1940
>> +#define DC_OVERLAY_COLOR_TABLE_INDEX		0x1980
>> +#define DC_OVERLAY_COLOR_TABLE_DATA			0x19C0
>> +#define DC_OVERLAY_SRC_GLOBAL_COLOR			0x16C0
>> +#define DC_OVERLAY_DST_GLOBAL_COLOR			0x1700
>> +#define DC_OVERLAY_ROI_ORIGIN				0x1D00
>> +#define DC_OVERLAY_ROI_SIZE					0x1D40
>> +#define DC_OVERLAY_WATER_MARK				0x1DC0
>> +#define DC_OVERLAY_DEGAMMA_INDEX			0x2200
>> +#define DC_OVERLAY_DEGAMMA_DATA				0x2240
>> +#define DC_OVERLAY_DEGAMMA_EX_DATA			0x2280
>> +#define DC_OVERLAY_YUVTORGB_COEF0			0x1EC0
>> +#define DC_OVERLAY_YUVTORGB_COEF1			0x1F00
>> +#define DC_OVERLAY_YUVTORGB_COEF2			0x1F40
>> +#define DC_OVERLAY_YUVTORGB_COEF3			0x1F80
>> +#define DC_OVERLAY_YUVTORGB_COEF4			0x1FC0
>> +#define DC_OVERLAY_YUVTORGB_COEFD0			0x2000
>> +#define DC_OVERLAY_YUVTORGB_COEFD1			0x2040
>> +#define DC_OVERLAY_YUVTORGB_COEFD2			0x2080
>> +#define DC_OVERLAY_Y_CLAMP_BOUND			0x22C0
>> +#define DC_OVERLAY_UV_CLAMP_BOUND			0x2300
>> +#define DC_OVERLAY_RGBTORGB_COEF0			0x20C0
>> +#define DC_OVERLAY_RGBTORGB_COEF1			0x2100
>> +#define DC_OVERLAY_RGBTORGB_COEF2			0x2140
>> +#define DC_OVERLAY_RGBTORGB_COEF3			0x2180
>> +#define DC_OVERLAY_RGBTORGB_COEF4			0x21C0
>> +
>> +#define DC_CURSOR_CONFIG					0x1468
>> +#define DC_CURSOR_ADDRESS					0x146C
>> +#define DC_CURSOR_LOCATION					0x1470
>> +#define DC_CURSOR_BACKGROUND				0x1474
>> +#define DC_CURSOR_FOREGROUND				0x1478
>> +#define DC_CURSOR_CLK_GATING				0x1484
>> +#define DC_CURSOR_CONFIG_EX					0x24E8
>> +#define DC_CURSOR_OFFSET					0x1080
>> +
>> +#define DC_DISPLAY_DITHER_CONFIG		0x1410
>> +#define DC_DISPLAY_PANEL_CONFIG			0x1418
>> +#define DC_DISPLAY_PANEL_CONFIG_EX		0x2518
>> +#define DC_DISPLAY_DITHER_TABLE_LOW		0x1420
>> +#define DC_DISPLAY_DITHER_TABLE_HIGH	0x1428
>> +#define DC_DISPLAY_H					0x1430
>> +#define DC_DISPLAY_H_SYNC				0x1438
>> +#define DC_DISPLAY_V					0x1440
>> +#define DC_DISPLAY_V_SYNC				0x1448
>> +#define DC_DISPLAY_CURRENT_LOCATION		0x1450
>> +#define DC_DISPLAY_GAMMA_INDEX			0x1458
>> +#define DC_DISPLAY_GAMMA_DATA			0x1460
>> +#define DC_DISPLAY_INT					0x147C
>> +#define DC_DISPLAY_INT_ENABLE			0x1480
>> +#define DC_DISPLAY_DBI_CONFIG			0x1488
>> +#define DC_DISPLAY_GENERAL_CONFIG		0x14B0
>> +#define DC_DISPLAY_DPI_CONFIG			0x14B8
>> +#define DC_DISPLAY_PANEL_START			0x1CCC
>> +#define DC_DISPLAY_DEBUG_COUNTER_SELECT		0x14D0
>> +#define DC_DISPLAY_DEBUG_COUNTER_VALUE		0x14D8
>> +#define DC_DISPLAY_DP_CONFIG				0x1CD0
>> +#define DC_DISPLAY_GAMMA_EX_INDEX			0x1CF0
>> +#define DC_DISPLAY_GAMMA_EX_DATA			0x1CF8
>> +#define DC_DISPLAY_GAMMA_EX_ONE_DATA		0x1D80
>> +#define DC_DISPLAY_RGBTOYUV_COEF0			0x1E48
>> +#define DC_DISPLAY_RGBTOYUV_COEF1			0x1E50
>> +#define DC_DISPLAY_RGBTOYUV_COEF2			0x1E58
>> +#define DC_DISPLAY_RGBTOYUV_COEF3			0x1E60
>> +#define DC_DISPLAY_RGBTOYUV_COEF4			0x1E68
>> +#define DC_DISPLAY_RGBTOYUV_COEFD0			0x1E70
>> +#define DC_DISPLAY_RGBTOYUV_COEFD1			0x1E78
>> +#define DC_DISPLAY_RGBTOYUV_COEFD2			0x1E80
>> +
>> +#define DC_CLK_GATTING					0x1A28
>> +#define DC_QOS_CONFIG					0x1A38
>> +
>> +#define DC_TRANSPARENCY_OPAQUE			0x00
>> +#define DC_TRANSPARENCY_KEY				0x02
>> +#define DC_DISPLAY_DITHERTABLE_LOW		0x7B48F3C0
>> +#define DC_DISPLAY_DITHERTABLE_HIGH		0x596AD1E2
>> +
>> +#define GAMMA_SIZE						256
>> +#define GAMMA_EX_SIZE					300
>> +#define DEGAMMA_SIZE					260
>> +
>> +#define RGB_TO_RGB_TABLE_SIZE			9
>> +#define YUV_TO_RGB_TABLE_SIZE			16
>> +#define RGB_TO_YUV_TABLE_SIZE			12
>> +
>> +#define DC_LAYER_NUM	6
>> +#define DC_DISPLAY_NUM	2
>> +#define DC_CURSOR_NUM	2
>> +
>> +#define DC_TILE_MODE4X4	0x15
>> +
>> +enum dc_chip_rev {
>> +	DC_REV_0,/* For HW_REV_5720,HW_REV_5721_311 */
>> +	DC_REV_1,/* For HW_REV_5721_30B */
>> +	DC_REV_2,/* For HW_REV_5721_310 */
>> +};
>> +
>> +enum dc_hw_plane_id {
>> +	PRIMARY_PLANE_0,
>> +	OVERLAY_PLANE_0,
>> +	OVERLAY_PLANE_1,
>> +	PRIMARY_PLANE_1,
>> +	OVERLAY_PLANE_2,
>> +	OVERLAY_PLANE_3,
>> +	CURSOR_PLANE_0,
>> +	CURSOR_PLANE_1,
>> +	PLANE_NUM
>> +};
>> +
>> +enum dc_hw_color_format {
>> +	FORMAT_X4R4G4B4,//0
> 
> Space after the comma will make it more readable. Or just define the 
> values explicitly, it will also be more readable.
> 
>> +	FORMAT_A4R4G4B4,//1
>> +	FORMAT_X1R5G5B5,//2
>> +	FORMAT_A1R5G5B5,//3
>> +	FORMAT_R5G6B5,//4
>> +	FORMAT_X8R8G8B8,//5
>> +	FORMAT_A8R8G8B8,//6
>> +	FORMAT_YUY2,//7
>> +	FORMAT_UYVY,//8
>> +	FORMAT_INDEX8,//9
>> +	FORMAT_MONOCHROME,//10
>> +	FORMAT_YV12 = 0xf,
>> +	FORMAT_A8,//16
>> +	FORMAT_NV12,//17
>> +	FORMAT_NV16,//18
>> +	FORMAT_RG16,//19
>> +	FORMAT_R8,//20
>> +	FORMAT_NV12_10BIT,//21
>> +	FORMAT_A2R10G10B10,//22
>> +	FORMAT_NV16_10BIT,//23
>> +	FORMAT_INDEX1,//24
>> +	FORMAT_INDEX2,//25
>> +	FORMAT_INDEX4,//26
>> +	FORMAT_P010,//27
>> +	FORMAT_YUV444,//28
>> +	FORMAT_YUV444_10BIT,//29
>> +};
>> +
>> +enum dc_hw_yuv_color_space {
>> +	COLOR_SPACE_601 = 0,
>> +	COLOR_SPACE_709 = 1,
>> +	COLOR_SPACE_2020 = 3,
>> +};
>> +
>> +enum dc_hw_rotation {
>> +	ROT_0 = 0,
>> +	ROT_90 = 4,
>> +	ROT_180 = 5,
>> +	ROT_270 = 6,
>> +	FLIP_X = 1,
>> +	FLIP_Y = 2,
>> +	FLIP_XY = 3,
>> +};
>> +
>> +enum dc_hw_swizzle {
>> +	SWIZZLE_ARGB = 0,
>> +	SWIZZLE_RGBA,
>> +	SWIZZLE_ABGR,
>> +	SWIZZLE_BGRA,
>> +};
>> +
>> +enum dc_hw_out {
>> +	OUT_DPI,
>> +	OUT_DP,
>> +};
>> +
>> +enum dc_hw_cursor_size {
>> +	CURSOR_SIZE_32X32 = 0,
>> +	CURSOR_SIZE_64X64,
>> +};
>> +
>> +enum dc_hw_blend_mode {
>> +	/* out.rgb = plane_alpha * fg.rgb +
>> +	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
>> +	 */
>> +	BLEND_PREMULTI,
>> +	/* out.rgb = plane_alpha * fg.alpha * fg.rgb +
>> +	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
>> +	 */
>> +	BLEND_COVERAGE,
>> +	/* out.rgb = plane_alpha * fg.rgb +
>> +	 *		(1 - plane_alpha) * bg.rgb
>> +	 */
>> +	BLEND_PIXEL_NONE,
> 
> Can you use defines from <drm/drm_blend.h>?
> 
>> +};
>> +
>> +struct dc_hw_plane_reg {
>> +	u32 y_address;
>> +	u32 u_address;
>> +	u32 v_address;
>> +	u32 y_stride;
>> +	u32 u_stride;
>> +	u32 v_stride;
>> +	u32 size;
>> +	u32 top_left;
>> +	u32 bottom_right;
>> +	u32 scale_factor_x;
>> +	u32 scale_factor_y;
>> +	u32 h_filter_coef_index;
>> +	u32 h_filter_coef_data;
>> +	u32 v_filter_coef_index;
>> +	u32 v_filter_coef_data;
>> +	u32 init_offset;
>> +	u32 color_key;
>> +	u32 color_key_high;
>> +	u32 clear_value;
>> +	u32 color_table_index;
>> +	u32 color_table_data;
>> +	u32 scale_config;
>> +	u32 water_mark;
>> +	u32 degamma_index;
>> +	u32 degamma_data;
>> +	u32 degamma_ex_data;
>> +	u32 src_global_color;
>> +	u32 dst_global_color;
>> +	u32 blend_config;
>> +	u32 roi_origin;
>> +	u32 roi_size;
>> +	u32 yuv_to_rgb_coef0;
>> +	u32 yuv_to_rgb_coef1;
>> +	u32 yuv_to_rgb_coef2;
>> +	u32 yuv_to_rgb_coef3;
>> +	u32 yuv_to_rgb_coef4;
>> +	u32 yuv_to_rgb_coefd0;
>> +	u32 yuv_to_rgb_coefd1;
>> +	u32 yuv_to_rgb_coefd2;
>> +	u32 y_clamp_bound;
>> +	u32 uv_clamp_bound;
>> +	u32 rgb_to_rgb_coef0;
>> +	u32 rgb_to_rgb_coef1;
>> +	u32 rgb_to_rgb_coef2;
>> +	u32 rgb_to_rgb_coef3;
>> +	u32 rgb_to_rgb_coef4;
>> +};
>> +
>> +struct dc_hw_fb {
>> +	u32 y_address;
>> +	u32 u_address;
>> +	u32 v_address;
>> +	u32 clear_value;
>> +	u32 water_mark;
>> +	u16 y_stride;
>> +	u16 u_stride;
>> +	u16 v_stride;
>> +	u16 width;
>> +	u16 height;
>> +	u8	format;
>> +	u8	tile_mode;
>> +	u8	rotation;
>> +	u8	yuv_color_space;
>> +	u8	swizzle;
>> +	u8	uv_swizzle;
>> +	u8	zpos;
>> +	u8	display_id;
>> +	bool	clear_enable;
>> +	bool	dec_enable;
>> +	bool	enable;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_scale {
>> +	u32 scale_factor_x;
>> +	u32 scale_factor_y;
>> +	bool	enable;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_position {
>> +	u16 start_x;
>> +	u16 start_y;
>> +	u16 end_x;
>> +	u16 end_y;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_blend {
>> +	u8	alpha;
>> +	u8	blend_mode;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_colorkey {
>> +	u32 colorkey;
>> +	u32 colorkey_high;
>> +	u8	transparency;
>> +	bool dirty;
>> +};
>> +
>> +struct dc_hw_roi {
>> +	u16 x;
>> +	u16 y;
>> +	u16 width;
>> +	u16 height;
>> +	bool enable;
>> +	bool dirty;
>> +};
>> +
>> +struct dc_hw_cursor {
>> +	u32 address;
>> +	u16 x;
>> +	u16 y;
>> +	u16 hot_x;
>> +	u16 hot_y;
>> +	u8	size;
>> +	u8	display_id;
>> +	bool	enable;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_display {
>> +	u32 bus_format;
>> +	u16 h_active;
>> +	u16 h_total;
>> +	u16 h_sync_start;
>> +	u16 h_sync_end;
>> +	u16 v_active;
>> +	u16 v_total;
>> +	u16 v_sync_start;
>> +	u16 v_sync_end;
>> +	u8	id;
>> +	bool	h_sync_polarity;
>> +	bool	v_sync_polarity;
>> +	bool	enable;
>> +};
>> +
>> +struct dc_hw_gamma {
>> +	u16 gamma[GAMMA_EX_SIZE][3];
>> +	bool	enable;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_degamma {
>> +	u16 degamma[DEGAMMA_SIZE][3];
>> +	u32 mode;
>> +	bool	dirty;
>> +};
>> +
>> +struct dc_hw_plane {
>> +	struct dc_hw_fb			fb;
>> +	struct dc_hw_position	pos;
>> +	struct dc_hw_scale		scale;
>> +	struct dc_hw_blend		blend;
>> +	struct dc_hw_roi		roi;
>> +	struct dc_hw_colorkey	colorkey;
>> +	struct dc_hw_degamma	degamma;
>> +};
>> +
>> +struct dc_hw_qos {
>> +	u8	  low_value;
>> +	u8	  high_value;
>> +	bool  dirty;
>> +};
>> +
>> +struct dc_hw_read {
>> +	u32			reg;
>> +	u32			value;
>> +};
>> +
>> +struct dc_hw;
>> +struct dc_hw_funcs {
>> +	void (*gamma)(struct dc_hw *hw);
>> +	void (*plane)(struct dc_hw *hw);
>> +	void (*display)(struct dc_hw *hw, struct dc_hw_display *display);
>> +};
>> +
>> +struct dc_hw {
>> +	enum dc_chip_rev rev;
>> +	enum dc_hw_out		out[DC_DISPLAY_NUM];
>> +	void			*hi_base;
>> +	void			*reg_base;
>> +
>> +	struct dc_hw_display display[DC_DISPLAY_NUM];
>> +	struct dc_hw_gamma	 gamma[DC_DISPLAY_NUM];
>> +	struct dc_hw_plane	 plane[DC_LAYER_NUM];
>> +	struct dc_hw_cursor  cursor[DC_CURSOR_NUM];
>> +	struct dc_hw_qos	 qos;
>> +	struct dc_hw_funcs	 *func;
>> +	struct vs_dc_info	 *info;
>> +};
>> +
>> +int dc_hw_init(struct dc_hw *hw);
>> +void dc_hw_deinit(struct dc_hw *hw);
>> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
>> +			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
>> +			struct dc_hw_position *pos, struct dc_hw_blend *blend);
>> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode);
>> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi);
>> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
>> +			   struct dc_hw_colorkey *colorkey);
>> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos);
>> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor);
>> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
>> +			u16 r, u16 g, u16 b);
>> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
>> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display);
>> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable);
>> +u32 dc_hw_get_interrupt(struct dc_hw *hw);
>> +bool dc_hw_check_underflow(struct dc_hw *hw);
>> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable);
>> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
>> +void dc_hw_commit(struct dc_hw *hw);
>> +
>> +#endif /* __VS_DC_HW_H__ */
>> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
>> index da7698c3d..3cd533cfa 100644
>> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
>> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
>> @@ -21,6 +21,7 @@
>>   
>>   #include "vs_drv.h"
>>   #include "vs_modeset.h"
>> +#include "vs_dc.h"
>>   
>>   #define DRV_NAME	"verisilicon"
>>   #define DRV_DESC	"Verisilicon DRM driver"
>> @@ -123,6 +124,7 @@ static const struct component_master_ops vs_drm_ops = {
>>   };
>>   
>>   static struct platform_driver *drm_sub_drivers[] = {
>> +	&dc_platform_driver,
>>   
>>   };
>>   
>> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
>> new file mode 100644
>> index 000000000..9bd066015
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_plane.c
>> @@ -0,0 +1,526 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_blend.h>
>> +#include <drm/drm_gem_dma_helper.h>
>> +#include <drm/drm_fb_dma_helper.h>
>> +#include <drm/drm_framebuffer.h>
>> +#include <drm/drm_plane.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <drm/vs_drm.h>
>> +
>> +#include "vs_plane.h"
>> +#include "vs_drv.h"
>> +#include "vs_dc.h"
>> +
>> +static void vs_plane_reset(struct drm_plane *plane)
>> +{
>> +	struct vs_plane_state *state;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +
>> +	if (plane->state) {
>> +		__drm_atomic_helper_plane_destroy_state(plane->state);
>> +
>> +		state = to_vs_plane_state(plane->state);
>> +		kfree(state);
>> +		plane->state = NULL;
>> +	}
>> +
> 
> Use vs_plane_destroy_state directly. This way you won't miss a refcount 
> on blobs.
> 
>> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +	if (!state)
>> +		return;
>> +
>> +	state->degamma = VS_DEGAMMA_DISABLE;
>> +	state->degamma_changed = false;
>> +	state->base.zpos = vs_plane->id;
>> +	memset(&state->status, 0, sizeof(state->status));
>> +
>> +	__drm_atomic_helper_plane_reset(plane, &state->base);
>> +}
>> +
>> +static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
>> +				     struct vs_plane_state *ori_state)
>> +{
>> +	state->watermark = ori_state->watermark;
>> +	state->color_mgmt = ori_state->color_mgmt;
>> +	state->roi = ori_state->roi;
>> +
>> +	if (state->watermark)
>> +		drm_property_blob_get(state->watermark);
>> +	if (state->color_mgmt)
>> +		drm_property_blob_get(state->color_mgmt);
>> +	if (state->roi)
>> +		drm_property_blob_get(state->roi);
>> +}
>> +
>> +static int
>> +_vs_plane_set_property_blob_from_id(struct drm_device *dev,
>> +				    struct drm_property_blob **blob,
>> +				    u64 blob_id,
>> +				    size_t expected_size)
>> +{
>> +	struct drm_property_blob *new_blob = NULL;
>> +
>> +	if (blob_id) {
>> +		new_blob = drm_property_lookup_blob(dev, blob_id);
>> +		if (!new_blob)
>> +			return -EINVAL;
>> +
>> +		if (new_blob->length != expected_size) {
>> +			drm_property_blob_put(new_blob);
>> +			return -EINVAL;
>> +		}
>> +	}
>> +
>> +	drm_property_replace_blob(blob, new_blob);
>> +	drm_property_blob_put(new_blob);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct drm_plane_state *
>> +vs_plane_atomic_duplicate_state(struct drm_plane *plane)
>> +{
>> +	struct vs_plane_state *ori_state;
>> +	struct vs_plane_state *state;
>> +
>> +	if (WARN_ON(!plane->state))
>> +		return NULL;
>> +
>> +	ori_state = to_vs_plane_state(plane->state);
>> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +	if (!state)
>> +		return NULL;
>> +
>> +	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
>> +
>> +	state->degamma = ori_state->degamma;
>> +	state->degamma_changed = ori_state->degamma_changed;
>> +
>> +	_vs_plane_duplicate_blob(state, ori_state);
>> +	memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
>> +
>> +	return &state->base;
>> +}
>> +
>> +static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
>> +					  struct drm_plane_state *state)
>> +{
>> +	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
>> +
>> +	__drm_atomic_helper_plane_destroy_state(state);
>> +
>> +	drm_property_blob_put(vs_plane_state->watermark);
>> +	drm_property_blob_put(vs_plane_state->color_mgmt);
>> +	drm_property_blob_put(vs_plane_state->roi);
>> +	kfree(vs_plane_state);
>> +}
>> +
>> +static int vs_plane_atomic_set_property(struct drm_plane *plane,
>> +					struct drm_plane_state *state,
>> +					struct drm_property *property,
>> +					uint64_t val)
>> +{
>> +	struct drm_device *dev = plane->dev;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
>> +	int ret = 0;
>> +
>> +	if (property == vs_plane->degamma_mode) {
>> +		if (vs_plane_state->degamma != val) {
>> +			vs_plane_state->degamma = val;
>> +			vs_plane_state->degamma_changed = true;
>> +		} else {
>> +			vs_plane_state->degamma_changed = false;
>> +		}
>> +	} else if (property == vs_plane->watermark_prop) {
>> +		ret = _vs_plane_set_property_blob_from_id(dev,
>> +							  &vs_plane_state->watermark,
>> +							  val,
>> +							  sizeof(struct drm_vs_watermark));
>> +		return ret;
>> +	} else if (property == vs_plane->color_mgmt_prop) {
>> +		ret = _vs_plane_set_property_blob_from_id(dev,
>> +							  &vs_plane_state->color_mgmt,
>> +							  val,
>> +							  sizeof(struct drm_vs_color_mgmt));
>> +		return ret;
>> +	} else if (property == vs_plane->roi_prop) {
>> +		ret = _vs_plane_set_property_blob_from_id(dev,
>> +							  &vs_plane_state->roi,
>> +							  val,
>> +							  sizeof(struct drm_vs_roi));
>> +		return ret;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int vs_plane_atomic_get_property(struct drm_plane *plane,
>> +					const struct drm_plane_state *state,
>> +					struct drm_property *property,
>> +					uint64_t *val)
>> +{
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	const struct vs_plane_state *vs_plane_state =
>> +		container_of(state, const struct vs_plane_state, base);
>> +
>> +	if (property == vs_plane->degamma_mode)
>> +		*val = vs_plane_state->degamma;
>> +	else if (property == vs_plane->watermark_prop)
>> +		*val = (vs_plane_state->watermark) ?
>> +					vs_plane_state->watermark->base.id : 0;
>> +	else if (property == vs_plane->color_mgmt_prop)
>> +		*val = (vs_plane_state->color_mgmt) ?
>> +					vs_plane_state->color_mgmt->base.id : 0;
> 
> degamma and color management should use standard properties.
> 
>> +	else if (property == vs_plane->roi_prop)
>> +		*val = (vs_plane_state->roi) ?
>> +					vs_plane_state->roi->base.id : 0;
>> +	else
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static bool vs_format_mod_supported(struct drm_plane *plane,
>> +				    u32 format,
>> +				    u64 modifier)
>> +{
>> +	int i;
>> +
>> +	/* We always have to allow these modifiers:
>> +	 * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
>> +	 * 2. Not passing any modifiers is the same as explicitly passing INVALID.
>> +	 */
>> +	if (modifier == DRM_FORMAT_MOD_LINEAR)
>> +		return true;
>> +
>> +	/* Check that the modifier is on the list of the plane's supported modifiers. */
>> +	for (i = 0; i < plane->modifier_count; i++) {
>> +		if (modifier == plane->modifiers[i])
>> +			break;
>> +	}
>> +
>> +	if (i == plane->modifier_count)
>> +		return false;
>> +
>> +	return true;
>> +}
>> +
>> +const struct drm_plane_funcs vs_plane_funcs = {
>> +	.update_plane		= drm_atomic_helper_update_plane,
>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>> +	.reset			= vs_plane_reset,
>> +	.atomic_duplicate_state = vs_plane_atomic_duplicate_state,
>> +	.atomic_destroy_state	= vs_plane_atomic_destroy_state,
>> +	.atomic_set_property	= vs_plane_atomic_set_property,
>> +	.atomic_get_property	= vs_plane_atomic_get_property,
>> +	.format_mod_supported	= vs_format_mod_supported,
>> +};
>> +
>> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
>> +{
>> +	const struct drm_format_info *info;
>> +
>> +	if (!fb)
>> +		return 0;
>> +
>> +	info = drm_format_info(fb->format->format);
>> +	if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
>> +		return 0;
>> +
>> +	return info->num_planes;
>> +}
>> +
>> +static int vs_plane_atomic_check(struct drm_plane *plane,
>> +				 struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> +										 plane);
>> +	unsigned char i, num_planes;
>> +	struct drm_framebuffer *fb = new_plane_state->fb;
>> +	struct drm_crtc *crtc = new_plane_state->crtc;
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
>> +
>> +	if (!crtc || !fb)
>> +		return 0;
>> +
>> +	num_planes = vs_get_plane_number(fb);
>> +
>> +	for (i = 0; i < num_planes; i++) {
>> +		dma_addr_t dma_addr;
>> +
>> +		dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
>> +		plane_state->dma_addr[i] = dma_addr;
>> +	}
>> +
>> +	return vs_dc_check_plane(dc, plane, state);
>> +}
>> +
>> +static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
>> +					struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> +									  plane);
>> +	unsigned char i, num_planes;
>> +	struct drm_framebuffer *fb = new_plane_state->fb;
>> +	struct drm_crtc *crtc = new_plane_state->crtc;
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
>> +
>> +	if (!crtc || !fb)
>> +		return 0;
>> +
>> +	num_planes = vs_get_plane_number(fb);
>> +
>> +	for (i = 0; i < num_planes; i++) {
>> +		dma_addr_t dma_addr;
>> +
>> +		dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
>> +		plane_state->dma_addr[i] = dma_addr;
>> +	}
>> +
>> +	return vs_dc_check_cursor_plane(dc, plane, state);
>> +}
>> +
>> +static void vs_plane_atomic_update(struct drm_plane *plane,
>> +				   struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> +									  plane);
> 
> New line after the equal sign will be better.
> 
>> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> +									  plane);
>> +
>> +	unsigned char i, num_planes;
>> +	struct drm_framebuffer *fb;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	if (!new_state->fb || !new_state->crtc)
>> +		return;
> 
> if (!new_state->visible) ?
> 
>> +
>> +	fb = new_state->fb;
>> +
>> +	drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
>> +
>> +	num_planes = vs_get_plane_number(fb);
>> +
>> +	for (i = 0; i < num_planes; i++) {
>> +		dma_addr_t dma_addr;
>> +
>> +		dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
>> +		plane_state->dma_addr[i] = dma_addr;
>> +	}
>> +
>> +	plane_state->status.src = drm_plane_state_src(new_state);
>> +	plane_state->status.dest = drm_plane_state_dest(new_state);
>> +
>> +	vs_dc_update_plane(dc, vs_plane, plane, state);
>> +}
>> +
>> +static void vs_cursor_plane_atomic_update(struct drm_plane *plane,
>> +					  struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> +									   plane);
>> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> +									   plane);
>> +	unsigned char i, num_planes;
>> +	struct drm_framebuffer *fb;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
>> +	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	if (!new_state->fb || !new_state->crtc)
> 
> and here.
> 
>> +		return;
>> +
>> +	fb = new_state->fb;
>> +	drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
>> +
>> +	num_planes = vs_get_plane_number(fb);
>> +
>> +	for (i = 0; i < num_planes; i++) {
>> +		dma_addr_t dma_addr;
>> +
>> +		dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
>> +		plane_state->dma_addr[i] = dma_addr;
>> +	}
>> +
>> +	plane_state->status.src = drm_plane_state_src(new_state);
>> +	plane_state->status.dest = drm_plane_state_dest(new_state);
>> +
>> +	vs_dc_update_cursor_plane(dc, vs_plane, plane, state);
>> +}
>> +
>> +static void vs_plane_atomic_disable(struct drm_plane *plane,
>> +				    struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> +									   plane);
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	vs_dc_disable_plane(dc, vs_plane, old_state);
>> +}
>> +
>> +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane,
>> +					   struct drm_atomic_state *state)
>> +{
>> +	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> +									   plane);
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
>> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> +
>> +	vs_dc_disable_cursor_plane(dc, vs_plane, old_state);
>> +}
>> +
>> +const struct drm_plane_helper_funcs primary_plane_helpers = {
>> +	.atomic_check	= vs_plane_atomic_check,
>> +	.atomic_update	= vs_plane_atomic_update,
>> +	.atomic_disable = vs_plane_atomic_disable,
>> +};
>> +
>> +const struct drm_plane_helper_funcs overlay_plane_helpers = {
>> +	.atomic_check	= vs_plane_atomic_check,
>> +	.atomic_update	= vs_plane_atomic_update,
>> +	.atomic_disable = vs_plane_atomic_disable,
>> +};
>> +
>> +const struct drm_plane_helper_funcs cursor_plane_helpers = {
>> +	.atomic_check	= vs_cursor_plane_atomic_check,
>> +	.atomic_update	= vs_cursor_plane_atomic_update,
>> +	.atomic_disable = vs_cursor_plane_atomic_disable,
>> +};
>> +
>> +static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
>> +	{ VS_DEGAMMA_DISABLE,	"disabled" },
>> +	{ VS_DEGAMMA_BT709,	"preset degamma for BT709" },
>> +	{ VS_DEGAMMA_BT2020,	"preset degamma for BT2020" },
>> +};
>> +
>> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
>> +				 struct vs_plane_info *info,
>> +				 unsigned int layer_num,
>> +				 unsigned int possible_crtcs)
>> +{
>> +	struct vs_plane *plane;
>> +	int ret;
>> +
>> +	if (!info)
>> +		return NULL;
>> +
>> +	plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
>> +					   possible_crtcs,
>> +					   &vs_plane_funcs,
>> +					   info->formats, info->num_formats,
>> +					   info->modifiers, info->type,
>> +					   info->name ? info->name : NULL);
>> +	if (IS_ERR(plane))
>> +		return ERR_CAST(plane);
>> +
>> +	if (info->type == DRM_PLANE_TYPE_PRIMARY)
>> +		drm_plane_helper_add(&plane->base, &primary_plane_helpers);
>> +	else if (info->type == DRM_PLANE_TYPE_CURSOR)
>> +		drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
>> +	else
>> +		drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
>> +
>> +	/* Set up the plane properties */
>> +	if (info->degamma_size) {
>> +		plane->degamma_mode =
>> +		drm_property_create_enum(drm_dev, 0,
>> +					 "DEGAMMA_MODE",
>> +					 vs_degamma_mode_enum_list,
>> +					 ARRAY_SIZE(vs_degamma_mode_enum_list));
>> +
>> +		if (!plane->degamma_mode)
>> +			return NULL;
>> +
>> +		drm_object_attach_property(&plane->base.base,
>> +					   plane->degamma_mode,
>> +					   VS_DEGAMMA_DISABLE);
>> +	}
>> +
>> +	if (info->rotation) {
>> +		ret = drm_plane_create_rotation_property(&plane->base,
>> +							 DRM_MODE_ROTATE_0,
>> +							 info->rotation);
>> +		if (ret)
>> +			return NULL;
>> +	}
>> +
>> +	if (info->blend_mode) {
>> +		ret = drm_plane_create_blend_mode_property(&plane->base,
>> +							   info->blend_mode);
>> +		if (ret)
>> +			return NULL;
>> +		ret = drm_plane_create_alpha_property(&plane->base);
>> +		if (ret)
>> +			return NULL;
>> +	}
>> +
>> +	if (info->color_encoding) {
>> +		ret = drm_plane_create_color_properties(&plane->base,
>> +							info->color_encoding,
>> +							BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
>> +							DRM_COLOR_YCBCR_BT709,
>> +							DRM_COLOR_YCBCR_LIMITED_RANGE);
>> +		if (ret)
>> +			return NULL;
>> +	}
>> +
>> +	if (info->zpos != 255) {
>> +		ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
>> +						     layer_num - 1);
>> +		if (ret)
>> +			return NULL;
>> +	} else {
>> +		ret = drm_plane_create_zpos_immutable_property(&plane->base,
>> +							       info->zpos);
>> +		if (ret)
>> +			return NULL;
>> +	}
>> +
>> +	if (info->watermark) {
>> +		plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
>> +							    "WATERMARK", 0);
>> +		if (!plane->watermark_prop)
>> +			return NULL;
>> +		drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
>> +	}
>> +
>> +	if (info->color_mgmt) {
>> +		plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
>> +							     "COLOR_CONFIG", 0);
>> +		if (!plane->color_mgmt_prop)
>> +			return NULL;
>> +
>> +		drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
>> +	}
>> +
>> +	if (info->roi) {
>> +		plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
>> +						      "ROI", 0);
>> +		if (!plane->roi_prop)
>> +			return NULL;
>> +
>> +		drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
>> +	}
>> +
>> +	return plane;
>> +}
>> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
>> new file mode 100644
>> index 000000000..554b74e96
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_plane.h
>> @@ -0,0 +1,58 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_PLANE_H__
>> +#define __VS_PLANE_H__
>> +
>> +#include <drm/drm_fourcc.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include "vs_type.h"
>> +
>> +struct vs_plane_status {
>> +	u32 tile_mode;
>> +	struct drm_rect src;
>> +	struct drm_rect dest;
>> +};
>> +
>> +struct vs_plane_state {
>> +	struct drm_plane_state base;
>> +	struct vs_plane_status status; /* for debugfs */
>> +
>> +	struct drm_property_blob *watermark;
>> +	struct drm_property_blob *color_mgmt;
>> +	struct drm_property_blob *roi;
>> +	dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES];
>> +
>> +	u32 degamma;
>> +	bool degamma_changed;
>> +};
>> +
>> +struct vs_plane {
>> +	struct drm_plane base;
>> +	u8 id;
>> +
>> +	struct drm_property *degamma_mode;
>> +	struct drm_property *watermark_prop;
>> +	struct drm_property *color_mgmt_prop;
>> +	struct drm_property *roi_prop;
>> +};
>> +
>> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
>> +				 struct vs_plane_info *info,
>> +				 unsigned int layer_num,
>> +				 unsigned int possible_crtcs);
>> +
>> +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
>> +{
>> +	return container_of(plane, struct vs_plane, base);
>> +}
>> +
>> +static inline struct vs_plane_state *
>> +to_vs_plane_state(struct drm_plane_state *state)
>> +{
>> +	return container_of(state, struct vs_plane_state, base);
>> +}
>> +#endif /* __VS_PLANE_H__ */
>> diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
>> new file mode 100644
>> index 000000000..7d3378e29
>> --- /dev/null
>> +++ b/drivers/gpu/drm/verisilicon/vs_type.h
>> @@ -0,0 +1,69 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> + */
>> +
>> +#ifndef __VS_TYPE_H__
>> +#define __VS_TYPE_H__
>> +
>> +#include <drm/drm_plane.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +struct vs_plane_info {
>> +	const char *name;
>> +	u8 id;
>> +	enum drm_plane_type type;
>> +	unsigned int num_formats;
>> +	const u32 *formats;
>> +	u8 num_modifiers;
>> +	const u64 *modifiers;
>> +	unsigned int min_width;
>> +	unsigned int min_height;
>> +	unsigned int max_width;
>> +	unsigned int max_height;
>> +	unsigned int rotation;
>> +	unsigned int blend_mode;
>> +	unsigned int color_encoding;
>> +
>> +	/* 0 means no de-gamma LUT */
>> +	unsigned int degamma_size;
>> +
>> +	int min_scale; /* 16.16 fixed point */
>> +	int max_scale; /* 16.16 fixed point */
>> +
>> +	/* default zorder value,
>> +	 * and 255 means unsupported zorder capability
>> +	 */
>> +	u8	 zpos;
>> +
>> +	bool watermark;
>> +	bool color_mgmt;
>> +	bool roi;
>> +};
>> +
>> +struct vs_dc_info {
>> +	const char *name;
>> +
>> +	u8 panel_num;
>> +
>> +	/* planes */
>> +	u8 plane_num;
>> +	const struct vs_plane_info *planes;
>> +
>> +	u8 layer_num;
>> +	unsigned int max_bpc;
>> +	unsigned int color_formats;
>> +
>> +	/* 0 means no gamma LUT */
>> +	u16 gamma_size;
>> +	u8 gamma_bits;
>> +
>> +	u16 pitch_alignment;
>> +
>> +	bool pipe_sync;
>> +	bool background;
>> +	bool panel_sync;
>> +	bool cap_dec;
>> +};
>> +
>> +#endif /* __VS_TYPE_H__ */
>
Dmitry Baryshkov Nov. 14, 2023, 10:59 a.m. UTC | #2
On Tue, 14 Nov 2023 at 12:42, Keith Zhao <keith.zhao@starfivetech.com> wrote:
>
>
>
> On 2023/10/26 3:28, Dmitry Baryshkov wrote:
> > On 25/10/2023 13:39, Keith Zhao wrote:
> >> add 2 crtcs and 8 planes in vs-drm
> >>
> >> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> >> ---
> >>   drivers/gpu/drm/verisilicon/Makefile   |    8 +-
> >>   drivers/gpu/drm/verisilicon/vs_crtc.c  |  257 ++++
> >>   drivers/gpu/drm/verisilicon/vs_crtc.h  |   43 +
> >>   drivers/gpu/drm/verisilicon/vs_dc.c    | 1002 ++++++++++++
> >>   drivers/gpu/drm/verisilicon/vs_dc.h    |   80 +
> >>   drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1959 ++++++++++++++++++++++++
> >>   drivers/gpu/drm/verisilicon/vs_dc_hw.h |  492 ++++++
> >>   drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
> >>   drivers/gpu/drm/verisilicon/vs_plane.c |  526 +++++++
> >>   drivers/gpu/drm/verisilicon/vs_plane.h |   58 +
> >>   drivers/gpu/drm/verisilicon/vs_type.h  |   69 +
> >>   11 files changed, 4494 insertions(+), 2 deletions(-)
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
> >>
> >> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> >> index 7d3be305b..1d48016ca 100644
> >> --- a/drivers/gpu/drm/verisilicon/Makefile
> >> +++ b/drivers/gpu/drm/verisilicon/Makefile
> >> @@ -1,7 +1,11 @@
> >>   # SPDX-License-Identifier: GPL-2.0
> >>
> >> -vs_drm-objs := vs_drv.o \
> >> -            vs_modeset.o
> >> +vs_drm-objs := vs_dc_hw.o \
> >> +            vs_dc.o \
> >> +            vs_crtc.o \
> >> +            vs_drv.o \
> >> +            vs_modeset.o \
> >> +            vs_plane.o
> >>
> >>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
> >>
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
> >> new file mode 100644
> >> index 000000000..8a658ea77
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
> >> @@ -0,0 +1,257 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + *
> >> + */
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/debugfs.h>
> >> +#include <linux/media-bus-format.h>
> >> +
> >> +#include <drm/drm_atomic_helper.h>
> >> +#include <drm/drm_atomic.h>
> >> +#include <drm/drm_crtc.h>
> >> +#include <drm/drm_gem_atomic_helper.h>
> >> +#include <drm/drm_vblank.h>
> >> +#include <drm/vs_drm.h>
> >> +
> >> +#include "vs_crtc.h"
> >> +#include "vs_dc.h"
> >> +#include "vs_drv.h"
> >> +
> >> +static void vs_crtc_reset(struct drm_crtc *crtc)
> >> +{
> >> +    struct vs_crtc_state *state;
> >> +
> >> +    if (crtc->state) {
> >> +            __drm_atomic_helper_crtc_destroy_state(crtc->state);
> >> +
> >> +            state = to_vs_crtc_state(crtc->state);
> >> +            kfree(state);
> >> +            crtc->state = NULL;
> >> +    }
> >
> > You can call your crtc_destroy_state function directly here.
> >
> >> +
> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
> >> +    if (!state)
> >> +            return;
> >> +
> >> +    __drm_atomic_helper_crtc_reset(crtc, &state->base);
> >> +}
> >> +
> >> +static struct drm_crtc_state *
> >> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
> >> +{
> >> +    struct vs_crtc_state *ori_state;
> >
> > It might be a matter of taste, but it is usually old_state.
> >
> >> +    struct vs_crtc_state *state;
> >> +
> >> +    if (!crtc->state)
> >> +            return NULL;
> >> +
> >> +    ori_state = to_vs_crtc_state(crtc->state);
> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
> >> +    if (!state)
> >> +            return NULL;
> >> +
> >> +    __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
> >> +
> >> +    state->output_fmt = ori_state->output_fmt;
> >> +    state->encoder_type = ori_state->encoder_type;
> >> +    state->bpp = ori_state->bpp;
> >> +    state->underflow = ori_state->underflow;
> >
> > Can you use kmemdup instead?
> >
> >> +
> >> +    return &state->base;
> >> +}
> >> +
> >> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
> >> +                                     struct drm_crtc_state *state)
> >> +{
> >> +    __drm_atomic_helper_crtc_destroy_state(state);
> >> +    kfree(to_vs_crtc_state(state));
> >> +}
> >> +
> >> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
> >> +{
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    vs_dc_enable_vblank(dc, true);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
> >> +{
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    vs_dc_enable_vblank(dc, false);
> >> +}
> >> +
> >> +static const struct drm_crtc_funcs vs_crtc_funcs = {
> >> +    .set_config             = drm_atomic_helper_set_config,
> >> +    .page_flip              = drm_atomic_helper_page_flip,
> >
> > destroy is required, see drm_mode_config_cleanup()
>
> hi Dmitry:
> if define destroy in drm_crtc_funcs,
> it will make __drmm_crtc_init_with_planes unhappy

Ack, I missed that you have been using drmm_crtc_init. BTW, I checked
your code, you should be able to switch drm
drmm_crtc_alloc_with_planes().

>
> see:
> __printf(6, 0)
> static int __drmm_crtc_init_with_planes(struct drm_device *dev,
>                                         struct drm_crtc *crtc,
>                                         struct drm_plane *primary,
>                                         struct drm_plane *cursor,
>                                         const struct drm_crtc_funcs *funcs,
>                                         const char *name,
>                                         va_list args)
> {
>         int ret;
>
>         drm_WARN_ON(dev, funcs && funcs->destroy);
>
> ........
> }
>
> It should not need to be defined here, I think
>
> >
> >> +    .reset                  = vs_crtc_reset,
> >> +    .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
> >> +    .atomic_destroy_state   = vs_crtc_atomic_destroy_state,
> >
> > please consider adding atomic_print_state to output driver-specific bits.
> >
> >> +    .enable_vblank          = vs_crtc_enable_vblank,
> >> +    .disable_vblank         = vs_crtc_disable_vblank,
> >> +};
> >> +
> >> +static u8 cal_pixel_bits(u32 bus_format)
> >
> > This looks like a generic helper code, which can go to a common place.
> >
> >> +{
> >> +    u8 bpp;
> >> +
> >> +    switch (bus_format) {
> >> +    case MEDIA_BUS_FMT_RGB565_1X16:
> >> +    case MEDIA_BUS_FMT_UYVY8_1X16:
> >> +            bpp = 16;
> >> +            break;
> >> +    case MEDIA_BUS_FMT_RGB666_1X18:
> >> +    case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> >> +            bpp = 18;
> >> +            break;
> >> +    case MEDIA_BUS_FMT_UYVY10_1X20:
> >> +            bpp = 20;
> >> +            break;
> >> +    case MEDIA_BUS_FMT_BGR888_1X24:
> >> +    case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> >> +    case MEDIA_BUS_FMT_YUV8_1X24:
> >> +            bpp = 24;
> >> +            break;
> >> +    case MEDIA_BUS_FMT_RGB101010_1X30:
> >> +    case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> >> +    case MEDIA_BUS_FMT_YUV10_1X30:
> >> +            bpp = 30;
> >> +            break;
> >> +    default:
> >> +            bpp = 24;
> >> +            break;
> >> +    }
> >> +
> >> +    return bpp;
> >> +}
> >> +
> >> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
> >> +                              struct drm_atomic_state *state)
> >> +{
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
> >> +
> >> +    vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
> >> +
> >> +    vs_dc_enable(dc, crtc);
> >> +    drm_crtc_vblank_on(crtc);
> >> +}
> >> +
> >> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
> >> +                               struct drm_atomic_state *state)
> >> +{
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    drm_crtc_vblank_off(crtc);
> >> +
> >> +    vs_dc_disable(dc, crtc);
> >> +
> >> +    if (crtc->state->event && !crtc->state->active) {
> >> +            spin_lock_irq(&crtc->dev->event_lock);
> >> +            drm_crtc_send_vblank_event(crtc, crtc->state->event);
> >> +            spin_unlock_irq(&crtc->dev->event_lock);
> >> +
> >> +            crtc->state->event = NULL;
> >
> > I think even should be cleared within the lock.
> >
> >> +    }
> >> +}
> >> +
> >> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
> >> +                             struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> >> +                                                                      crtc);
> >> +
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct device *dev = vs_crtc->dev;
> >> +    struct drm_property_blob *blob = crtc->state->gamma_lut;
> >> +    struct drm_color_lut *lut;
> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
> >> +
> >> +    if (crtc_state->color_mgmt_changed) {
> >> +            if (blob && blob->length) {
> >> +                    lut = blob->data;
> >> +                    vs_dc_set_gamma(dc, crtc, lut,
> >> +                                    blob->length / sizeof(*lut));
> >> +                    vs_dc_enable_gamma(dc, crtc, true);
> >> +            } else {
> >> +                    vs_dc_enable_gamma(dc, crtc, false);
> >> +            }
> >> +    }
> >> +}
> >> +
> >> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
> >> +                             struct drm_atomic_state *state)
> >> +{
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct drm_pending_vblank_event *event = crtc->state->event;
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    vs_dc_commit(dc);
> >> +
> >> +    if (event) {
> >> +            WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> >> +
> >> +            spin_lock_irq(&crtc->dev->event_lock);
> >> +            drm_crtc_arm_vblank_event(crtc, event);
> >> +            spin_unlock_irq(&crtc->dev->event_lock);
> >> +            crtc->state->event = NULL;
> >
> > I think even should be cleared within the lock.
> >
> >> +    }
> >> +}
> >> +
> >> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
> >> +    .atomic_check = drm_crtc_helper_atomic_check,
> >> +    .atomic_enable  = vs_crtc_atomic_enable,
> >> +    .atomic_disable = vs_crtc_atomic_disable,
> >> +    .atomic_begin   = vs_crtc_atomic_begin,
> >> +    .atomic_flush   = vs_crtc_atomic_flush,
> >> +};
> >> +
> >> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
> >> +    { VS_SINGLE_DC,                         "single dc mode" },
> >> +    { VS_MULTI_DC_PRIMARY,          "primary dc for multi dc mode" },
> >> +    { VS_MULTI_DC_SECONDARY,        "secondary dc for multi dc mode" },
> >> +};
> >> +
> >> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> >> +                           struct vs_dc_info *info)
> >> +{
> >> +    struct vs_crtc *crtc;
> >> +    int ret;
> >> +
> >> +    if (!info)
> >> +            return NULL;
> >> +
> >> +    crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL);
> >> +    if (!crtc)
> >> +            return NULL;
> >> +
> >> +    ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base,
> >> +                                     NULL, NULL, &vs_crtc_funcs,
> >> +                                     info->name ? info->name : NULL);
> >
> > It might be better to add drmm_crtc_init() helper.
> >
> >> +    if (ret)
> >> +            return NULL;
> >> +
> >> +    drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
> >> +
> >> +    if (info->gamma_size) {
> >> +            ret = drm_mode_crtc_set_gamma_size(&crtc->base,
> >> +                                               info->gamma_size);
> >> +            if (ret)
> >> +                    return NULL;
> >> +
> >> +            drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
> >> +                                       info->gamma_size);
> >> +    }
> >> +
> >> +    crtc->max_bpc = info->max_bpc;
> >> +    crtc->color_formats = info->color_formats;
> >> +    return crtc;
> >> +}
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
> >> new file mode 100644
> >> index 000000000..526dd63e5
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
> >> @@ -0,0 +1,43 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#ifndef __VS_CRTC_H__
> >> +#define __VS_CRTC_H__
> >> +
> >> +#include <drm/drm_crtc.h>
> >> +#include <drm/drm_crtc_helper.h>
> >> +
> >> +#include "vs_type.h"
> >> +
> >> +struct vs_crtc_state {
> >> +    struct drm_crtc_state base;
> >> +
> >> +    u32 output_fmt;
> >> +    u8 encoder_type;
> >> +    u8 bpp;
> >> +    bool underflow;
> >> +};
> >> +
> >> +struct vs_crtc {
> >> +    struct drm_crtc base;
> >> +    struct device *dev;
> >> +    unsigned int max_bpc;
> >> +    unsigned int color_formats;
> >> +};
> >> +
> >> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> >> +                           struct vs_dc_info *info);
> >> +
> >> +static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
> >> +{
> >> +    return container_of(crtc, struct vs_crtc, base);
> >> +}
> >> +
> >> +static inline struct vs_crtc_state *
> >> +to_vs_crtc_state(struct drm_crtc_state *state)
> >> +{
> >> +    return container_of(state, struct vs_crtc_state, base);
> >> +}
> >> +#endif /* __VS_CRTC_H__ */
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
> >> new file mode 100644
> >> index 000000000..b5ab92d98
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc.c
> >> @@ -0,0 +1,1002 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#include <linux/component.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/pm_runtime.h>
> >> +#include <linux/reset.h>
> >> +
> >> +#include <drm/drm_atomic.h>
> >> +#include <drm/drm_atomic_helper.h>
> >> +#include <drm/drm_blend.h>
> >> +#include <drm/drm_framebuffer.h>
> >> +#include <drm/drm_vblank.h>
> >> +#include <drm/vs_drm.h>
> >> +
> >> +#include "vs_dc_hw.h"
> >> +#include "vs_dc.h"
> >> +#include "vs_drv.h"
> >> +
> >> +static const char * const vout_clocks[] = {
> >> +    "noc_bus",
> >> +    "channel0",
> >> +    "channel1",
> >> +    "dc_core",
> >> +    "axi_core",
> >> +    "ahb",
> >> +    "hdmi_tx",
> >> +    "dc_parent",
> >> +
> >> +};
> >> +
> >> +static const char * const vout_resets[] = {
> >> +    "axi",
> >> +    "ahb",
> >> +    "core",
> >> +};
> >> +
> >> +static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
> >> +{
> >> +    u8 f = FORMAT_A8R8G8B8;
> >> +
> >> +    switch (format) {
> >> +    case DRM_FORMAT_XRGB4444:
> >> +    case DRM_FORMAT_RGBX4444:
> >> +    case DRM_FORMAT_XBGR4444:
> >> +    case DRM_FORMAT_BGRX4444:
> >> +            f = FORMAT_X4R4G4B4;
> >> +            break;
> >> +    case DRM_FORMAT_ARGB4444:
> >> +    case DRM_FORMAT_RGBA4444:
> >> +    case DRM_FORMAT_ABGR4444:
> >> +    case DRM_FORMAT_BGRA4444:
> >> +            f = FORMAT_A4R4G4B4;
> >> +            break;
> >> +    case DRM_FORMAT_XRGB1555:
> >> +    case DRM_FORMAT_RGBX5551:
> >> +    case DRM_FORMAT_XBGR1555:
> >> +    case DRM_FORMAT_BGRX5551:
> >> +            f = FORMAT_X1R5G5B5;
> >> +            break;
> >> +    case DRM_FORMAT_ARGB1555:
> >> +    case DRM_FORMAT_RGBA5551:
> >> +    case DRM_FORMAT_ABGR1555:
> >> +    case DRM_FORMAT_BGRA5551:
> >> +            f = FORMAT_A1R5G5B5;
> >> +            break;
> >> +    case DRM_FORMAT_RGB565:
> >> +    case DRM_FORMAT_BGR565:
> >> +            f = FORMAT_R5G6B5;
> >> +            break;
> >> +    case DRM_FORMAT_XRGB8888:
> >> +    case DRM_FORMAT_RGBX8888:
> >> +    case DRM_FORMAT_XBGR8888:
> >> +    case DRM_FORMAT_BGRX8888:
> >> +            f = FORMAT_X8R8G8B8;
> >> +            break;
> >> +    case DRM_FORMAT_ARGB8888:
> >> +    case DRM_FORMAT_RGBA8888:
> >> +    case DRM_FORMAT_ABGR8888:
> >> +    case DRM_FORMAT_BGRA8888:
> >> +            f = FORMAT_A8R8G8B8;
> >> +            break;
> >> +    case DRM_FORMAT_YUYV:
> >> +    case DRM_FORMAT_YVYU:
> >> +            f = FORMAT_YUY2;
> >> +            break;
> >> +    case DRM_FORMAT_UYVY:
> >> +    case DRM_FORMAT_VYUY:
> >> +            f = FORMAT_UYVY;
> >> +            break;
> >> +    case DRM_FORMAT_YUV420:
> >> +    case DRM_FORMAT_YVU420:
> >> +            f = FORMAT_YV12;
> >> +            break;
> >> +    case DRM_FORMAT_NV21:
> >> +            f = FORMAT_NV12;
> >> +            break;
> >> +    case DRM_FORMAT_NV16:
> >> +    case DRM_FORMAT_NV61:
> >> +            f = FORMAT_NV16;
> >> +            break;
> >> +    case DRM_FORMAT_P010:
> >> +            f = FORMAT_P010;
> >> +            break;
> >> +    case DRM_FORMAT_ARGB2101010:
> >> +    case DRM_FORMAT_RGBA1010102:
> >> +    case DRM_FORMAT_ABGR2101010:
> >> +    case DRM_FORMAT_BGRA1010102:
> >> +            f = FORMAT_A2R10G10B10;
> >> +            break;
> >> +    case DRM_FORMAT_NV12:
> >> +            f = FORMAT_NV12;
> >> +            break;
> >> +    case DRM_FORMAT_YUV444:
> >> +            f = FORMAT_YUV444;
> >> +            break;
> >> +    default:
> >> +            break;
> >> +    }
> >> +
> >> +    fb->format = f;
> >> +}
> >> +
> >> +static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
> >> +{
> >> +    fb->swizzle = SWIZZLE_ARGB;
> >> +    fb->uv_swizzle = 0;
> >> +
> >> +    switch (format) {
> >> +    case DRM_FORMAT_RGBX4444:
> >> +    case DRM_FORMAT_RGBA4444:
> >> +    case DRM_FORMAT_RGBX5551:
> >> +    case DRM_FORMAT_RGBA5551:
> >> +    case DRM_FORMAT_RGBX8888:
> >> +    case DRM_FORMAT_RGBA8888:
> >> +    case DRM_FORMAT_RGBA1010102:
> >> +            fb->swizzle = SWIZZLE_RGBA;
> >> +            break;
> >> +    case DRM_FORMAT_XBGR4444:
> >> +    case DRM_FORMAT_ABGR4444:
> >> +    case DRM_FORMAT_XBGR1555:
> >> +    case DRM_FORMAT_ABGR1555:
> >> +    case DRM_FORMAT_BGR565:
> >> +    case DRM_FORMAT_XBGR8888:
> >> +    case DRM_FORMAT_ABGR8888:
> >> +    case DRM_FORMAT_ABGR2101010:
> >> +            fb->swizzle = SWIZZLE_ABGR;
> >> +            break;
> >> +    case DRM_FORMAT_BGRX4444:
> >> +    case DRM_FORMAT_BGRA4444:
> >> +    case DRM_FORMAT_BGRX5551:
> >> +    case DRM_FORMAT_BGRA5551:
> >> +    case DRM_FORMAT_BGRX8888:
> >> +    case DRM_FORMAT_BGRA8888:
> >> +    case DRM_FORMAT_BGRA1010102:
> >> +            fb->swizzle = SWIZZLE_BGRA;
> >> +            break;
> >> +    case DRM_FORMAT_YVYU:
> >> +    case DRM_FORMAT_VYUY:
> >> +    case DRM_FORMAT_NV21:
> >> +    case DRM_FORMAT_NV61:
> >> +            fb->uv_swizzle = 1;
> >> +            break;
> >> +    default:
> >> +            break;
> >> +    }
> >> +}
> >> +
> >> +static inline void update_watermark(struct drm_property_blob *watermark,
> >> +                                struct dc_hw_fb *fb)
> >> +{
> >> +    struct drm_vs_watermark *data;
> >> +
> >> +    fb->water_mark = 0;
> >> +
> >> +    if (watermark) {
> >> +            data = watermark->data;
> >> +            fb->water_mark = data->watermark & 0xFFFFF;
> >> +    }
> >> +}
> >> +
> >> +static inline u8 to_vs_rotation(unsigned int rotation)
> >> +{
> >> +    u8 rot;
> >> +
> >> +    switch (rotation & DRM_MODE_REFLECT_MASK) {
> >> +    case DRM_MODE_REFLECT_X:
> >> +            rot = FLIP_X;
> >> +            return rot;
> >> +    case DRM_MODE_REFLECT_Y:
> >> +            rot = FLIP_Y;
> >> +            return rot;
> >> +    case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
> >> +            rot = FLIP_XY;
> >> +            return rot;
> >> +    default:
> >> +            break;
> >> +    }
> >> +
> >> +    switch (rotation & DRM_MODE_ROTATE_MASK) {
> >> +    case DRM_MODE_ROTATE_0:
> >> +            rot = ROT_0;
> >> +            break;
> >> +    case DRM_MODE_ROTATE_90:
> >> +            rot = ROT_90;
> >> +            break;
> >> +    case DRM_MODE_ROTATE_180:
> >> +            rot = ROT_180;
> >> +            break;
> >> +    case DRM_MODE_ROTATE_270:
> >> +            rot = ROT_270;
> >> +            break;
> >> +    default:
> >> +            rot = ROT_0;
> >> +            break;
> >> +    }
> >> +
> >> +    return rot;
> >> +}
> >> +
> >> +static inline u8 to_vs_yuv_color_space(u32 color_space)
> >> +{
> >> +    u8 cs;
> >> +
> >> +    switch (color_space) {
> >> +    case DRM_COLOR_YCBCR_BT601:
> >> +            cs = COLOR_SPACE_601;
> >> +            break;
> >> +    case DRM_COLOR_YCBCR_BT709:
> >> +            cs = COLOR_SPACE_709;
> >> +            break;
> >> +    case DRM_COLOR_YCBCR_BT2020:
> >> +            cs = COLOR_SPACE_2020;
> >> +            break;
> >> +    default:
> >> +            cs = COLOR_SPACE_601;
> >> +            break;
> >> +    }
> >> +
> >> +    return cs;
> >> +}
> >> +
> >> +static inline u8 to_vs_tile_mode(u64 modifier)
> >> +{
> >> +    if (modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
> >> +            return DC_TILE_MODE4X4;
> >> +
> >> +    return (u8)(modifier & DRM_FORMAT_MOD_VERISILICON_NORM_MODE_MASK);
> >> +}
> >> +
> >> +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
> >> +{
> >> +    u8 panel_num = dc->hw.info->panel_num;
> >> +    u32 index = drm_crtc_index(crtc);
> >> +    int i;
> >> +
> >> +    for (i = 0; i < panel_num; i++) {
> >> +            if (index == dc->crtc[i]->base.index)
> >> +                    return i;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> >> +                                      unsigned int alignment)
> >> +{
> >> +    struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
> >> +
> >> +    if (alignment > priv->pitch_alignment)
> >> +            priv->pitch_alignment = alignment;
> >> +}
> >> +
> >> +static int plda_clk_rst_init(struct device *dev)
> >> +{
> >> +    int ret = 0;
> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
> >> +
> >> +    ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
> >> +    if (ret) {
> >> +            dev_err(dev, "failed to enable clocks\n");
> >> +            return ret;
> >> +    }
> >> +
> >> +    ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
> >> +    return ret;
> >> +}
> >> +
> >> +static void plda_clk_rst_deinit(struct device *dev)
> >> +{
> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
> >> +
> >> +    reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
> >> +    clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
> >> +}
> >> +
> >> +static void dc_deinit(struct device *dev)
> >> +{
> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
> >> +
> >> +    dc_hw_enable_interrupt(&dc->hw, 0);
> >> +    dc_hw_deinit(&dc->hw);
> >> +    plda_clk_rst_deinit(dev);
> >> +}
> >> +
> >> +static int dc_init(struct device *dev)
> >> +{
> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
> >> +    int ret;
> >> +
> >> +    dc->first_frame = true;
> >> +
> >> +    ret = plda_clk_rst_init(dev);
> >> +    if (ret < 0) {
> >> +            dev_err(dev, "failed to init dc clk reset: %d\n", ret);
> >> +            return ret;
> >> +    }
> >> +
> >> +    ret = dc_hw_init(&dc->hw);
> >> +    if (ret) {
> >> +            dev_err(dev, "failed to init DC HW\n");
> >> +            return ret;
> >> +    }
> >> +    return 0;
> >> +}
> >> +
> >> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc)
> >> +{
> >> +    struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
> >> +    struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> >> +    struct dc_hw_display display;
> >> +
> >> +    display.bus_format = crtc_state->output_fmt;
> >> +    display.h_active = mode->hdisplay;
> >> +    display.h_total = mode->htotal;
> >> +    display.h_sync_start = mode->hsync_start;
> >> +    display.h_sync_end = mode->hsync_end;
> >> +    if (mode->flags & DRM_MODE_FLAG_PHSYNC)
> >> +            display.h_sync_polarity = true;
> >> +    else
> >> +            display.h_sync_polarity = false;
> >> +
> >> +    display.v_active = mode->vdisplay;
> >> +    display.v_total = mode->vtotal;
> >> +    display.v_sync_start = mode->vsync_start;
> >> +    display.v_sync_end = mode->vsync_end;
> >> +
> >> +    if (mode->flags & DRM_MODE_FLAG_PVSYNC)
> >> +            display.v_sync_polarity = true;
> >> +    else
> >> +            display.v_sync_polarity = false;
> >> +
> >> +    display.id = to_vs_display_id(dc, crtc);
> >> +
> >> +    display.enable = true;
> >> +
> >> +    if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
> >> +            dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
> >> +            clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
> >> +            clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
> >> +                           dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
> >> +    } else {
> >> +            dc_hw_set_out(&dc->hw, OUT_DP, display.id);
> >> +            clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
> >> +                           dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
> >> +    }
> >> +
> >> +    dc_hw_setup_display(&dc->hw, &display);
> >> +}
> >> +
> >> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc)
> >> +{
> >> +    struct dc_hw_display display;
> >> +
> >> +    display.id = to_vs_display_id(dc, crtc);
> >> +    display.enable = false;
> >> +
> >> +    dc_hw_setup_display(&dc->hw, &display);
> >> +}
> >> +
> >> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> >> +                 struct drm_color_lut *lut, unsigned int size)
> >> +{
> >> +    u16 i, r, g, b;
> >> +    u8 bits, id;
> >> +
> >> +    if (size != dc->hw.info->gamma_size) {
> >> +            drm_err(crtc->dev, "gamma size does not match!\n");
> >> +            return;
> >> +    }
> >> +
> >> +    id = to_vs_display_id(dc, crtc);
> >> +
> >> +    bits = dc->hw.info->gamma_bits;
> >> +    for (i = 0; i < size; i++) {
> >> +            r = drm_color_lut_extract(lut[i].red, bits);
> >> +            g = drm_color_lut_extract(lut[i].green, bits);
> >> +            b = drm_color_lut_extract(lut[i].blue, bits);
> >> +            dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
> >> +    }
> >> +}
> >> +
> >> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> >> +                    bool enable)
> >> +{
> >> +    u8 id;
> >> +
> >> +    id = to_vs_display_id(dc, crtc);
> >> +    dc_hw_enable_gamma(&dc->hw, id, enable);
> >> +}
> >> +
> >> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable)
> >> +{
> >> +    dc_hw_enable_interrupt(&dc->hw, enable);
> >> +}
> >> +
> >> +static u32 calc_factor(u32 src, u32 dest)
> >> +{
> >> +    u32 factor = 1 << 16;
> >> +
> >> +    if (src > 1 && dest > 1)
> >> +            factor = ((src - 1) << 16) / (dest - 1);
> >> +
> >> +    return factor;
> >> +}
> >> +
> >> +static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
> >> +                     struct dc_hw_scale *scale)
> >> +{
> >> +    int dst_w = drm_rect_width(&state->dst);
> >> +    int dst_h = drm_rect_height(&state->dst);
> >> +    int src_w, src_h, temp;
> >> +
> >> +    scale->enable = false;
> >> +
> >> +    if (roi->enable) {
> >> +            src_w = roi->width;
> >> +            src_h = roi->height;
> >> +    } else {
> >> +            src_w = drm_rect_width(&state->src) >> 16;
> >> +            src_h = drm_rect_height(&state->src) >> 16;
> >> +    }
> >> +
> >> +    if (drm_rotation_90_or_270(state->rotation)) {
> >> +            temp = src_w;
> >> +            src_w = src_h;
> >> +            src_h = temp;
> >> +    }
> >> +
> >> +    if (src_w != dst_w) {
> >> +            scale->scale_factor_x = calc_factor(src_w, dst_w);
> >> +            scale->enable = true;
> >> +    } else {
> >> +            scale->scale_factor_x = 1 << 16;
> >> +    }
> >> +    if (src_h != dst_h) {
> >> +            scale->scale_factor_y = calc_factor(src_h, dst_h);
> >> +            scale->enable = true;
> >> +    } else {
> >> +            scale->scale_factor_y = 1 << 16;
> >> +    }
> >> +}
> >> +
> >> +static void update_fb(struct vs_plane *plane, u8 display_id,
> >> +                  struct dc_hw_fb *fb, struct drm_plane_state *state)
> >> +{
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
> >> +    struct drm_framebuffer *drm_fb = state->fb;
> >> +    struct drm_rect *src = &state->src;
> >> +
> >> +    fb->display_id = display_id;
> >> +    fb->y_address = plane_state->dma_addr[0];
> >> +    fb->y_stride = drm_fb->pitches[0];
> >> +    if (drm_fb->format->format == DRM_FORMAT_YVU420) {
> >> +            fb->u_address = plane_state->dma_addr[2];
> >> +            fb->v_address = plane_state->dma_addr[1];
> >> +            fb->u_stride = drm_fb->pitches[2];
> >> +            fb->v_stride = drm_fb->pitches[1];
> >> +    } else {
> >> +            fb->u_address = plane_state->dma_addr[1];
> >> +            fb->v_address = plane_state->dma_addr[2];
> >> +            fb->u_stride = drm_fb->pitches[1];
> >> +            fb->v_stride = drm_fb->pitches[2];
> >> +    }
> >> +    fb->width = drm_rect_width(src) >> 16;
> >> +    fb->height = drm_rect_height(src) >> 16;
> >> +    fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
> >> +    fb->rotation = to_vs_rotation(state->rotation);
> >> +    fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
> >> +    fb->zpos = state->zpos;
> >> +    fb->enable = state->visible;
> >> +    update_format(drm_fb->format->format, drm_fb->modifier, fb);
> >> +    update_swizzle(drm_fb->format->format, fb);
> >> +    update_watermark(plane_state->watermark, fb);
> >> +    plane_state->status.tile_mode = fb->tile_mode;
> >> +}
> >> +
> >> +static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
> >> +                       struct vs_plane_state *plane_state)
> >> +{
> >> +    dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
> >> +    plane_state->degamma_changed = false;
> >> +}
> >> +
> >> +static void update_roi(struct vs_dc *dc, u8 id,
> >> +                   struct vs_plane_state *plane_state,
> >> +                   struct dc_hw_roi *roi,
> >> +                   struct drm_plane_state *state)
> >> +{
> >> +    struct drm_vs_roi *data;
> >> +    struct drm_rect *src = &state->src;
> >> +    u16 src_w = drm_rect_width(src) >> 16;
> >> +    u16 src_h = drm_rect_height(src) >> 16;
> >> +
> >> +    if (plane_state->roi) {
> >> +            data = plane_state->roi->data;
> >> +
> >> +            if (data->enable) {
> >> +                    roi->x = data->roi_x;
> >> +                    roi->y = data->roi_y;
> >> +                    roi->width = (data->roi_x + data->roi_w > src_w) ?
> >> +                                             (src_w - data->roi_x) : data->roi_w;
> >> +                    roi->height = (data->roi_y + data->roi_h > src_h) ?
> >> +                                              (src_h - data->roi_y) : data->roi_h;
> >> +                    roi->enable = true;
> >> +            } else {
> >> +                    roi->enable = false;
> >> +            }
> >> +
> >> +            dc_hw_update_roi(&dc->hw, id, roi);
> >> +    } else {
> >> +            roi->enable = false;
> >> +    }
> >> +}
> >> +
> >> +static void update_color_mgmt(struct vs_dc *dc, u8 id,
> >> +                          struct dc_hw_fb *fb,
> >> +                          struct vs_plane_state *plane_state)
> >> +{
> >> +    struct drm_vs_color_mgmt *data;
> >> +    struct dc_hw_colorkey colorkey;
> >> +
> >> +    if (plane_state->color_mgmt) {
> >> +            data = plane_state->color_mgmt->data;
> >> +
> >> +            fb->clear_enable = data->clear_enable;
> >> +            fb->clear_value = data->clear_value;
> >> +
> >> +            if (data->colorkey > data->colorkey_high)
> >> +                    data->colorkey = data->colorkey_high;
> >> +
> >> +            colorkey.colorkey = data->colorkey;
> >> +            colorkey.colorkey_high = data->colorkey_high;
> >> +            colorkey.transparency = (data->transparency) ?
> >> +                            DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
> >> +            dc_hw_update_colorkey(&dc->hw, id, &colorkey);
> >> +    }
> >> +}
> >> +
> >> +static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                     struct drm_plane *drm_plane,
> >> +                     struct drm_atomic_state *drm_state)
> >> +{
> >> +    struct dc_hw_fb fb = {0};
> >> +    struct dc_hw_scale scale;
> >> +    struct dc_hw_position pos;
> >> +    struct dc_hw_blend blend;
> >> +    struct dc_hw_roi roi;
> >> +    struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> >> +                                                                       drm_plane);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
> >> +    struct drm_rect *dest = &state->dst;
> >> +    bool dec_enable = false;
> >> +    u8 display_id = 0;
> >> +
> >> +    display_id = to_vs_display_id(dc, state->crtc);
> >> +    update_fb(plane, display_id, &fb, state);
> >> +    fb.dec_enable = dec_enable;
> >> +
> >> +    update_roi(dc, plane->id, plane_state, &roi, state);
> >> +
> >> +    update_scale(state, &roi, &scale);
> >> +
> >> +    if (plane_state->degamma_changed)
> >> +            update_degamma(dc, plane, plane_state);
> >> +
> >> +    pos.start_x = dest->x1;
> >> +    pos.start_y = dest->y1;
> >> +    pos.end_x = dest->x2;
> >> +    pos.end_y = dest->y2;
> >> +
> >> +    blend.alpha = (u8)(state->alpha >> 8);
> >> +    blend.blend_mode = (u8)(state->pixel_blend_mode);
> >> +
> >> +    update_color_mgmt(dc, plane->id, &fb, plane_state);
> >> +
> >> +    dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
> >> +}
> >> +
> >> +static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
> >> +                   struct drm_plane *drm_plane,
> >> +                   struct drm_atomic_state *drm_state)
> >> +{
> >> +    struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> >> +                                                                       drm_plane);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
> >> +    struct drm_vs_watermark *data;
> >> +    struct dc_hw_qos qos;
> >> +
> >> +    if (plane_state->watermark) {
> >> +            data = plane_state->watermark->data;
> >> +
> >> +            if (data->qos_high) {
> >> +                    if (data->qos_low > data->qos_high)
> >> +                            data->qos_low = data->qos_high;
> >> +
> >> +                    qos.low_value = data->qos_low & 0x0F;
> >> +                    qos.high_value = data->qos_high & 0x0F;
> >> +                    dc_hw_update_qos(&dc->hw, &qos);
> >> +            }
> >> +    }
> >> +}
> >> +
> >> +static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
> >> +{
> >> +    u8 size_type;
> >> +
> >> +    switch (state->crtc_w) {
> >> +    case 32:
> >> +            size_type = CURSOR_SIZE_32X32;
> >> +            break;
> >> +    case 64:
> >> +            size_type = CURSOR_SIZE_64X64;
> >> +            break;
> >> +    default:
> >> +            size_type = CURSOR_SIZE_32X32;
> >> +            break;
> >> +    }
> >> +
> >> +    cursor->size = size_type;
> >> +}
> >> +
> >> +static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                            struct drm_plane *drm_plane,
> >> +                            struct drm_atomic_state *drm_state)
> >> +{
> >> +    struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> >> +                                                                   drm_plane);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
> >> +    struct drm_framebuffer *drm_fb = state->fb;
> >> +    struct dc_hw_cursor cursor;
> >> +
> >> +    cursor.address = plane_state->dma_addr[0];
> >> +    cursor.x = state->crtc_x;
> >> +    cursor.y = state->crtc_y;
> >> +    cursor.hot_x = drm_fb->hot_x;
> >> +    cursor.hot_y = drm_fb->hot_y;
> >> +    cursor.display_id = to_vs_display_id(dc, state->crtc);
> >> +    update_cursor_size(state, &cursor);
> >> +    cursor.enable = true;
> >> +
> >> +    dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
> >> +}
> >> +
> >> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                    struct drm_plane *drm_plane,
> >> +                    struct drm_atomic_state *drm_state)
> >> +{
> >> +    update_plane(dc, plane, drm_plane, drm_state);
> >> +    update_qos(dc, plane, drm_plane, drm_state);
> >> +}
> >> +
> >> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                           struct drm_plane *drm_plane,
> >> +                           struct drm_atomic_state *drm_state)
> >> +{
> >> +    update_cursor_plane(dc, plane, drm_plane, drm_state);
> >> +}
> >> +
> >> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                     struct drm_plane_state *old_state)
> >> +{
> >> +    struct dc_hw_fb fb = {0};
> >> +
> >> +    fb.enable = false;
> >> +    dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
> >> +}
> >> +
> >> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                            struct drm_plane_state *old_state)
> >> +{
> >> +    struct dc_hw_cursor cursor = {0};
> >> +
> >> +    cursor.enable = false;
> >> +    cursor.display_id = to_vs_display_id(dc, old_state->crtc);
> >> +    dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
> >> +}
> >> +
> >> +static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
> >> +                            u64 modifier)
> >> +{
> >> +    const u64 *mods;
> >> +
> >> +    if (!plane_info->modifiers)
> >> +            return false;
> >> +
> >> +    for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
> >> +            if (*mods == modifier)
> >> +                    return true;
> >> +    }
> >> +
> >> +    return false;
> >> +}
> >> +
> >> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
> >> +                  struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >> +                                                                             plane);
> >> +
> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
> >> +    const struct vs_plane_info *plane_info;
> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
> >> +    struct drm_crtc_state *crtc_state;
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +
> >> +    plane_info = &dc->hw.info->planes[vs_plane->id];
> >> +
> >> +    if (fb->width < plane_info->min_width ||
> >> +        fb->width > plane_info->max_width ||
> >> +        fb->height < plane_info->min_height ||
> >> +        fb->height > plane_info->max_height)
> >> +            drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
> >> +                         vs_plane->id);
> >> +
> >> +    if (!vs_dc_mod_supported(plane_info, fb->modifier)) {
> >> +            drm_err(plane->dev, "unsupported modifier on plane%d.\n", vs_plane->id);
> >> +            return -EINVAL;
> >> +    }
> >> +
> >> +    crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
> >> +    return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> >> +                                              plane_info->min_scale,
> >> +                                              plane_info->max_scale,
> >> +                                              true, true);
> >> +}
> >> +
> >> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
> >> +                         struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >> +                                                                       plane);
> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
> >> +    const struct vs_plane_info *plane_info;
> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
> >> +    struct drm_crtc_state *crtc_state;
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +
> >> +    plane_info = &dc->hw.info->planes[vs_plane->id];
> >> +
> >> +    if (fb->width < plane_info->min_width ||
> >> +        fb->width > plane_info->max_width ||
> >> +        fb->height < plane_info->min_height ||
> >> +        fb->height > plane_info->max_height)
> >> +            drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", vs_plane->id);
> >> +
> >> +    crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
> >> +    if (IS_ERR(crtc_state))
> >> +            return -EINVAL;
> >> +
> >> +    return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> >> +                                            plane_info->min_scale,
> >> +                                            plane_info->max_scale,
> >> +                                            true, true);
> >> +}
> >> +
> >> +static void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
> >> +{
> >> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
> >> +
> >> +    drm_crtc_handle_vblank(crtc);
> >> +
> >> +    vs_crtc_state->underflow = underflow;
> >> +}
> >> +
> >> +static irqreturn_t dc_isr(int irq, void *data)
> >> +{
> >> +    struct vs_dc *dc = data;
> >> +    struct vs_dc_info *dc_info = dc->hw.info;
> >> +    u32 i, ret;
> >> +
> >> +    ret = dc_hw_get_interrupt(&dc->hw);
> >> +
> >> +    for (i = 0; i < dc_info->panel_num; i++)
> >> +            vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
> >> +
> >> +    return IRQ_HANDLED;
> >> +}
> >> +
> >> +void vs_dc_commit(struct vs_dc *dc)
> >> +{
> >> +    dc_hw_enable_shadow_register(&dc->hw, false);
> >> +
> >> +    dc_hw_commit(&dc->hw);
> >> +
> >> +    if (dc->first_frame)
> >> +            dc->first_frame = false;
> >> +
> >> +    dc_hw_enable_shadow_register(&dc->hw, true);
> >> +}
> >> +
> >> +static int dc_bind(struct device *dev, struct device *master, void *data)
> >> +{
> >> +    struct drm_device *drm_dev = data;
> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
> >> +    struct device_node *port;
> >> +    struct vs_crtc *crtc;
> >> +    struct vs_dc_info *dc_info;
> >> +    struct vs_plane *plane;
> >> +    struct vs_plane_info *plane_info;
> >> +    int i, ret;
> >> +    u32 ctrc_mask = 0;
> >> +
> >> +    if (!drm_dev || !dc) {
> >> +            dev_err(dev, "devices are not created.\n");
> >> +            return -ENODEV;
> >> +    }
> >> +
> >> +    ret = dc_init(dev);
> >> +    if (ret < 0) {
> >> +            drm_err(drm_dev, "Failed to initialize DC hardware.\n");
> >> +            return ret;
> >> +    }
> >> +
> >> +    port = of_get_child_by_name(dev->of_node, "port");
> >> +    if (!port) {
> >> +            drm_err(drm_dev, "no port node found\n");
> >> +            return -ENODEV;
> >> +    }
> >> +    of_node_put(port);
> >> +
> >> +    dc_info = dc->hw.info;
> >> +
> >> +    for (i = 0; i < dc_info->panel_num; i++) {
> >> +            crtc = vs_crtc_create(drm_dev, dc_info);
> >> +            if (!crtc) {
> >> +                    drm_err(drm_dev, "Failed to create CRTC.\n");
> >> +                    ret = -ENOMEM;
> >> +                    return ret;
> >> +            }
> >> +
> >> +            crtc->base.port = port;
> >> +            crtc->dev = dev;
> >> +            dc->crtc[i] = crtc;
> >> +            ctrc_mask |= drm_crtc_mask(&crtc->base);
> >> +    }
> >> +
> >> +    for (i = 0; i < dc_info->plane_num; i++) {
> >> +            plane_info = (struct vs_plane_info *)&dc_info->planes[i];
> >> +
> >> +            if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
> >> +                    plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
> >> +                                            drm_crtc_mask(&dc->crtc[0]->base));
> >> +            } else if (!strcmp(plane_info->name, "Primary_1") ||
> >> +                               !strcmp(plane_info->name, "Cursor_1")) {
> >> +                    plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
> >> +                                            drm_crtc_mask(&dc->crtc[1]->base));
> >
> > I'd say, it's not typical to use name to distinguish objects. Maybe you
> > can add indices to the info structure and drop the names instead?
> >
> >
> >> +            } else {
> >> +                    plane = vs_plane_create(drm_dev, plane_info,
> >> +                                            dc_info->layer_num, ctrc_mask);
> >> +            }
> >> +
> >> +            if (IS_ERR(plane)) {
> >> +                    dev_err(dev, "failed to construct plane\n");
> >> +                    return PTR_ERR(plane);
> >> +            }
> >> +
> >> +            plane->id = i;
> >> +            dc->planes[i].id = plane_info->id;
> >> +
> >> +            if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
> >> +                    if (!strcmp(plane_info->name, "Primary"))
> >> +                            dc->crtc[0]->base.primary = &plane->base;
> >> +                    else
> >> +                            dc->crtc[1]->base.primary = &plane->base;
> >
> > This definitely urges for an index in the plane info / plane_state.
> >
> >> +                    drm_dev->mode_config.min_width = plane_info->min_width;
> >> +                    drm_dev->mode_config.min_height =
> >> +                                                    plane_info->min_height;
> >> +                    drm_dev->mode_config.max_width = plane_info->max_width;
> >> +                    drm_dev->mode_config.max_height =
> >> +                                                    plane_info->max_height;
> >> +            }
> >> +
> >> +            if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
> >> +                    if (!strcmp(plane_info->name, "Cursor"))
> >> +                            dc->crtc[0]->base.cursor = &plane->base;
> >> +                    else
> >> +                            dc->crtc[1]->base.cursor = &plane->base;
> >> +                    drm_dev->mode_config.cursor_width =
> >> +                                                    plane_info->max_width;
> >> +                    drm_dev->mode_config.cursor_height =
> >> +                                                    plane_info->max_height;
> >> +            }
> >> +    }
> >> +
> >> +    vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
> >> +    return 0;
> >> +}
> >> +
> >> +static void dc_unbind(struct device *dev, struct device *master, void *data)
> >> +{
> >> +    dc_deinit(dev);
> >> +}
> >> +
> >> +const struct component_ops dc_component_ops = {
> >> +    .bind = dc_bind,
> >> +    .unbind = dc_unbind,
> >> +};
> >> +
> >> +static const struct of_device_id dc_driver_dt_match[] = {
> >> +    { .compatible = "starfive,jh7110-dc8200", },
> >> +    {},
> >> +};
> >> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
> >> +
> >> +static int dc_probe(struct platform_device *pdev)
> >> +{
> >> +    struct device *dev = &pdev->dev;
> >> +    struct vs_dc *dc;
> >> +    int irq, ret, i;
> >> +
> >> +    dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
> >> +    if (!dc)
> >> +            return -ENOMEM;
> >> +
> >> +    dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
> >> +    if (IS_ERR(dc->hw.hi_base))
> >> +            return PTR_ERR(dc->hw.hi_base);
> >> +
> >> +    dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
> >> +    if (IS_ERR(dc->hw.reg_base))
> >> +            return PTR_ERR(dc->hw.reg_base);
> >> +
> >> +    dc->nclks = ARRAY_SIZE(dc->clk_vout);
> >> +    for (i = 0; i < dc->nclks; ++i)
> >> +            dc->clk_vout[i].id = vout_clocks[i];
> >> +    ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
> >> +    if (ret) {
> >> +            dev_err(dev, "Failed to get clk controls\n");
> >> +            return ret;
> >> +    }
> >> +
> >> +    dc->nrsts = ARRAY_SIZE(dc->rst_vout);
> >> +    for (i = 0; i < dc->nrsts; ++i)
> >> +            dc->rst_vout[i].id = vout_resets[i];
> >> +    ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
> >> +                                             dc->rst_vout);
> >> +    if (ret) {
> >> +            dev_err(dev, "Failed to get reset controls\n");
> >> +            return ret;
> >> +    }
> >> +
> >> +    irq = platform_get_irq(pdev, 0);
> >> +
> >> +    ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
> >
> > Are you ready to handle the IRQ at this point?
> >
> >> +    if (ret < 0) {
> >> +            dev_err(dev, "Failed to install irq:%u.\n", irq);
> >> +            return ret;
> >> +    }
> >> +
> >> +    dev_set_drvdata(dev, dc);
> >> +
> >> +    return component_add(dev, &dc_component_ops);
> >> +}
> >> +
> >> +static int dc_remove(struct platform_device *pdev)
> >> +{
> >> +    struct device *dev = &pdev->dev;
> >> +
> >> +    component_del(dev, &dc_component_ops);
> >> +
> >> +    dev_set_drvdata(dev, NULL);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +struct platform_driver dc_platform_driver = {
> >> +    .probe = dc_probe,
> >> +    .remove = dc_remove,
> >> +    .driver = {
> >> +            .name = "vs-dc",
> >> +            .of_match_table = of_match_ptr(dc_driver_dt_match),
> >> +    },
> >> +};
> >> +
> >> +MODULE_AUTHOR("StarFive Corporation");
> >> +MODULE_DESCRIPTION("VeriSilicon DC Driver");
> >> +MODULE_LICENSE("GPL");
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
> >> new file mode 100644
> >> index 000000000..8e96fd32c
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc.h
> >> @@ -0,0 +1,80 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#ifndef __VS_DC_H__
> >> +#define __VS_DC_H__
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/mm_types.h>
> >> +#include <linux/reset.h>
> >> +
> >> +#include <drm/drm_fourcc.h>
> >> +#include <drm/drm_modes.h>
> >> +
> >> +#include "vs_crtc.h"
> >> +#include "vs_dc_hw.h"
> >> +#include "vs_plane.h"
> >> +
> >> +struct vs_dc_plane {
> >> +    enum dc_hw_plane_id id;
> >> +};
> >> +
> >> +enum vout_clk {
> >> +    CLK_VOUT_NOC_DISP = 0,
> >> +    CLK_VOUT_PIX0,
> >> +    CLK_VOUT_PIX1,
> >> +    CLK_VOUT_CORE,
> >> +    CLK_VOUT_AXI,
> >> +    CLK_VOUT_AHB,
> >> +    CLK_VOUT_HDMI_PIX,
> >> +    CLK_VOUT_SOC_PIX,
> >> +    CLK_VOUT_NUM
> >> +};
> >> +
> >> +enum rst_vout {
> >> +    RST_VOUT_AXI = 0,
> >> +    RST_VOUT_AHB,
> >> +    RST_VOUT_CORE,
> >> +    RST_VOUT_NUM
> >> +};
> >> +
> >> +struct vs_dc {
> >> +    struct vs_crtc          *crtc[DC_DISPLAY_NUM];
> >> +    struct dc_hw            hw;
> >> +    bool                    first_frame;
> >> +
> >> +    struct vs_dc_plane      planes[PLANE_NUM];
> >> +    struct clk_bulk_data    clk_vout[CLK_VOUT_NUM];
> >> +    int                     nclks;
> >> +    struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
> >> +    int                     nrsts;
> >> +};
> >> +
> >> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc);
> >> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc);
> >> +
> >> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> >> +                 struct drm_color_lut *lut, unsigned int size);
> >> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc, bool enable);
> >> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable);
> >> +void vs_dc_commit(struct vs_dc *dc);
> >> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                    struct drm_plane *drm_plane,
> >> +                    struct drm_atomic_state *drm_state);
> >> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                     struct drm_plane_state *old_state);
> >> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
> >> +                  struct drm_atomic_state *state);
> >> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                           struct drm_plane *drm_plane,
> >> +                           struct drm_atomic_state *drm_state);
> >> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> >> +                            struct drm_plane_state *old_state);
> >> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
> >> +                         struct drm_atomic_state *state);
> >> +
> >> +extern struct platform_driver dc_platform_driver;
> >> +
> >> +#endif /* __VS_DC_H__ */
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> >> new file mode 100644
> >> index 000000000..e5acb7eb4
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> >> @@ -0,0 +1,1959 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#include <linux/bits.h>
> >> +#include <linux/io.h>
> >> +#include <linux/media-bus-format.h>
> >> +#include <drm/drm_atomic_helper.h>
> >> +#include <drm/drm_blend.h>
> >> +#include <drm/drm_fourcc.h>
> >> +#include <drm/vs_drm.h>
> >> +
> >> +#include "vs_dc_hw.h"
> >> +#include "vs_type.h"
> >> +
> >> +static const u32 horkernel[] = {
> >> +    0x00000000, 0x20000000, 0x00002000, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> >> +    0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x01470000,
> >> +    0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x00004000, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x20002000, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x14680000,
> >> +    0x00002b98, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x087f0000, 0x00003781, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x399a0666, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x021f0000,
> >> +};
> >> +
> >> +#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))
> >> +
> >> +static const u32 verkernel[] = {
> >> +    0x00000000, 0x20000000, 0x00002000, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> >> +    0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> >> +    0x00000000, 0x00000000, 0x00000000, 0x01470000,
> >> +    0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> >> +    0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> >> +    0x00000000, 0x00000000, 0x00004000, 0x00000000,
> >> +    0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
> >> +    0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
> >> +    0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> >> +};
> >> +
> >> +#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))
> >> +
> >> +/*
> >> + * RGB 709->2020 conversion parameters
> >> + */
> >> +static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
> >> +    10279,  5395,   709,
> >> +    1132,   15065,  187,
> >> +    269,    1442,   14674
> >> +};
> >> +
> >> +/*
> >> + * YUV601 to RGB conversion parameters
> >> + * YUV2RGB[0]  - [8] : C0 - C8;
> >> + * YUV2RGB[9]  - [11]: D0 - D2;
> >> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> >> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> >> + */
> >> +static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> >> +    1196,   0,                      1640,   1196,
> >> +    -404,   -836,           1196,   2076,
> >> +    0,              -916224,        558336, -1202944,
> >> +    64,              940,           64,             960
> >> +};
> >> +
> >> +/*
> >> + * YUV709 to RGB conversion parameters
> >> + * YUV2RGB[0]  - [8] : C0 - C8;
> >> + * YUV2RGB[9]  - [11]: D0 - D2;
> >> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> >> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> >> + */
> >> +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> >> +    1196,           0,              1844,   1196,
> >> +    -220,           -548,   1196,   2172,
> >> +    0,                      -1020672, 316672,  -1188608,
> >> +    64,                     940,            64,             960
> >> +};
> >> +
> >> +/*
> >> + * YUV2020 to RGB conversion parameters
> >> + * YUV2RGB[0]  - [8] : C0 - C8;
> >> + * YUV2RGB[9]  - [11]: D0 - D2;
> >> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> >> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> >> + */
> >> +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> >> +    1196, 0, 1724, 1196,
> >> +    -192, -668, 1196, 2200,
> >> +    0, -959232, 363776, -1202944,
> >> +    64, 940, 64, 960
> >> +};
> >> +
> >> +/*
> >> + * RGB to YUV2020 conversion parameters
> >> + * RGB2YUV[0] - [8] : C0 - C8;
> >> + * RGB2YUV[9] - [11]: D0 - D2;
> >> + */
> >> +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
> >> +    230,    594,    52,
> >> +    -125,  -323,    448,
> >> +    448,   -412,   -36,
> >> +    64,             512,    512
> >> +};
> >> +
> >> +/*
> >> + * Degamma table for 709 color space data.
> >> + */
> >> +static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
> >> +    0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
> >> +    0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
> >> +    0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
> >> +    0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
> >> +    0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
> >> +    0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
> >> +    0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
> >> +    0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
> >> +    0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
> >> +    0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
> >> +    0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
> >> +    0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
> >> +    0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
> >> +    0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
> >> +    0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
> >> +    0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
> >> +    0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
> >> +    0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
> >> +    0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
> >> +    0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
> >> +    0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
> >> +    0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
> >> +    0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
> >> +    0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
> >> +    0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
> >> +    0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
> >> +    0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
> >> +    0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
> >> +    0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
> >> +    0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
> >> +    0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
> >> +    0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
> >> +};
> >> +
> >> +/*
> >> + * Degamma table for 2020 color space data.
> >> + */
> >> +static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> >> +    0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
> >> +    0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
> >> +    0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
> >> +    0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
> >> +    0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
> >> +    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
> >> +    0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
> >> +    0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
> >> +    0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
> >> +    0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
> >> +    0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
> >> +    0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
> >> +    0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
> >> +    0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
> >> +    0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
> >> +    0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
> >> +    0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
> >> +    0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
> >> +    0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
> >> +    0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
> >> +    0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
> >> +    0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
> >> +    0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
> >> +    0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
> >> +    0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
> >> +    0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
> >> +    0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
> >> +    0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
> >> +    0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
> >> +    0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
> >> +};
> >> +
> >> +/* one is for primary plane and the other is for all overlay planes */
> >> +static const struct dc_hw_plane_reg dc_plane_reg[] = {
> >> +    {
> >> +    .y_address              = DC_FRAMEBUFFER_ADDRESS,
> >> +    .u_address              = DC_FRAMEBUFFER_U_ADDRESS,
> >> +    .v_address              = DC_FRAMEBUFFER_V_ADDRESS,
> >> +    .y_stride               = DC_FRAMEBUFFER_STRIDE,
> >> +    .u_stride               = DC_FRAMEBUFFER_U_STRIDE,
> >> +    .v_stride               = DC_FRAMEBUFFER_V_STRIDE,
> >> +    .size                   = DC_FRAMEBUFFER_SIZE,
> >> +    .top_left               = DC_FRAMEBUFFER_TOP_LEFT,
> >> +    .bottom_right   = DC_FRAMEBUFFER_BOTTOM_RIGHT,
> >> +    .scale_factor_x                 = DC_FRAMEBUFFER_SCALE_FACTOR_X,
> >> +    .scale_factor_y                 = DC_FRAMEBUFFER_SCALE_FACTOR_Y,
> >> +    .h_filter_coef_index    = DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
> >> +    .h_filter_coef_data             = DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
> >> +    .v_filter_coef_index    = DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
> >> +    .v_filter_coef_data             = DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
> >> +    .init_offset                    = DC_FRAMEBUFFER_INIT_OFFSET,
> >> +    .color_key                              = DC_FRAMEBUFFER_COLOR_KEY,
> >> +    .color_key_high                 = DC_FRAMEBUFFER_COLOR_KEY_HIGH,
> >> +    .clear_value                    = DC_FRAMEBUFFER_CLEAR_VALUE,
> >> +    .color_table_index              = DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
> >> +    .color_table_data               = DC_FRAMEBUFFER_COLOR_TABLE_DATA,
> >> +    .scale_config                   = DC_FRAMEBUFFER_SCALE_CONFIG,
> >> +    .water_mark                             = DC_FRAMEBUFFER_WATER_MARK,
> >> +    .degamma_index                  = DC_FRAMEBUFFER_DEGAMMA_INDEX,
> >> +    .degamma_data                   = DC_FRAMEBUFFER_DEGAMMA_DATA,
> >> +    .degamma_ex_data                = DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
> >> +    .src_global_color               = DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
> >> +    .dst_global_color               = DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
> >> +    .blend_config                   = DC_FRAMEBUFFER_BLEND_CONFIG,
> >> +    .roi_origin                             = DC_FRAMEBUFFER_ROI_ORIGIN,
> >> +    .roi_size                               = DC_FRAMEBUFFER_ROI_SIZE,
> >> +    .yuv_to_rgb_coef0                       = DC_FRAMEBUFFER_YUVTORGB_COEF0,
> >> +    .yuv_to_rgb_coef1                       = DC_FRAMEBUFFER_YUVTORGB_COEF1,
> >> +    .yuv_to_rgb_coef2                       = DC_FRAMEBUFFER_YUVTORGB_COEF2,
> >> +    .yuv_to_rgb_coef3                       = DC_FRAMEBUFFER_YUVTORGB_COEF3,
> >> +    .yuv_to_rgb_coef4                       = DC_FRAMEBUFFER_YUVTORGB_COEF4,
> >> +    .yuv_to_rgb_coefd0                      = DC_FRAMEBUFFER_YUVTORGB_COEFD0,
> >> +    .yuv_to_rgb_coefd1                      = DC_FRAMEBUFFER_YUVTORGB_COEFD1,
> >> +    .yuv_to_rgb_coefd2                      = DC_FRAMEBUFFER_YUVTORGB_COEFD2,
> >> +    .y_clamp_bound                          = DC_FRAMEBUFFER_Y_CLAMP_BOUND,
> >> +    .uv_clamp_bound                         = DC_FRAMEBUFFER_UV_CLAMP_BOUND,
> >> +    .rgb_to_rgb_coef0                       = DC_FRAMEBUFFER_RGBTORGB_COEF0,
> >> +    .rgb_to_rgb_coef1                       = DC_FRAMEBUFFER_RGBTORGB_COEF1,
> >> +    .rgb_to_rgb_coef2                       = DC_FRAMEBUFFER_RGBTORGB_COEF2,
> >> +    .rgb_to_rgb_coef3                       = DC_FRAMEBUFFER_RGBTORGB_COEF3,
> >> +    .rgb_to_rgb_coef4                       = DC_FRAMEBUFFER_RGBTORGB_COEF4,
> >> +    },
> >> +    {
> >> +    .y_address              = DC_OVERLAY_ADDRESS,
> >> +    .u_address              = DC_OVERLAY_U_ADDRESS,
> >> +    .v_address              = DC_OVERLAY_V_ADDRESS,
> >> +    .y_stride               = DC_OVERLAY_STRIDE,
> >> +    .u_stride               = DC_OVERLAY_U_STRIDE,
> >> +    .v_stride               = DC_OVERLAY_V_STRIDE,
> >> +    .size                   = DC_OVERLAY_SIZE,
> >> +    .top_left               = DC_OVERLAY_TOP_LEFT,
> >> +    .bottom_right   = DC_OVERLAY_BOTTOM_RIGHT,
> >> +    .scale_factor_x = DC_OVERLAY_SCALE_FACTOR_X,
> >> +    .scale_factor_y = DC_OVERLAY_SCALE_FACTOR_Y,
> >> +    .h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
> >> +    .h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
> >> +    .v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
> >> +    .v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
> >> +    .init_offset             = DC_OVERLAY_INIT_OFFSET,
> >> +    .color_key                       = DC_OVERLAY_COLOR_KEY,
> >> +    .color_key_high                 = DC_OVERLAY_COLOR_KEY_HIGH,
> >> +    .clear_value             = DC_OVERLAY_CLEAR_VALUE,
> >> +    .color_table_index       = DC_OVERLAY_COLOR_TABLE_INDEX,
> >> +    .color_table_data        = DC_OVERLAY_COLOR_TABLE_DATA,
> >> +    .scale_config            = DC_OVERLAY_SCALE_CONFIG,
> >> +    .water_mark                             = DC_OVERLAY_WATER_MARK,
> >> +    .degamma_index           = DC_OVERLAY_DEGAMMA_INDEX,
> >> +    .degamma_data            = DC_OVERLAY_DEGAMMA_DATA,
> >> +    .degamma_ex_data         = DC_OVERLAY_DEGAMMA_EX_DATA,
> >> +    .src_global_color        = DC_OVERLAY_SRC_GLOBAL_COLOR,
> >> +    .dst_global_color        = DC_OVERLAY_DST_GLOBAL_COLOR,
> >> +    .blend_config            = DC_OVERLAY_BLEND_CONFIG,
> >> +    .roi_origin                             = DC_OVERLAY_ROI_ORIGIN,
> >> +    .roi_size                               = DC_OVERLAY_ROI_SIZE,
> >> +    .yuv_to_rgb_coef0                = DC_OVERLAY_YUVTORGB_COEF0,
> >> +    .yuv_to_rgb_coef1                = DC_OVERLAY_YUVTORGB_COEF1,
> >> +    .yuv_to_rgb_coef2                = DC_OVERLAY_YUVTORGB_COEF2,
> >> +    .yuv_to_rgb_coef3                = DC_OVERLAY_YUVTORGB_COEF3,
> >> +    .yuv_to_rgb_coef4                       = DC_OVERLAY_YUVTORGB_COEF4,
> >> +    .yuv_to_rgb_coefd0                      = DC_OVERLAY_YUVTORGB_COEFD0,
> >> +    .yuv_to_rgb_coefd1                      = DC_OVERLAY_YUVTORGB_COEFD1,
> >> +    .yuv_to_rgb_coefd2                      = DC_OVERLAY_YUVTORGB_COEFD2,
> >> +    .y_clamp_bound           = DC_OVERLAY_Y_CLAMP_BOUND,
> >> +    .uv_clamp_bound          = DC_OVERLAY_UV_CLAMP_BOUND,
> >> +    .rgb_to_rgb_coef0                = DC_OVERLAY_RGBTORGB_COEF0,
> >> +    .rgb_to_rgb_coef1                = DC_OVERLAY_RGBTORGB_COEF1,
> >> +    .rgb_to_rgb_coef2                = DC_OVERLAY_RGBTORGB_COEF2,
> >> +    .rgb_to_rgb_coef3                = DC_OVERLAY_RGBTORGB_COEF3,
> >> +    .rgb_to_rgb_coef4                = DC_OVERLAY_RGBTORGB_COEF4,
> >> +    },
> >> +};
> >> +
> >> +static const u32 primary_overlay_format0[] = {
> >> +    DRM_FORMAT_XRGB4444,
> >> +    DRM_FORMAT_XBGR4444,
> >> +    DRM_FORMAT_RGBX4444,
> >> +    DRM_FORMAT_BGRX4444,
> >> +    DRM_FORMAT_ARGB4444,
> >> +    DRM_FORMAT_ABGR4444,
> >> +    DRM_FORMAT_RGBA4444,
> >> +    DRM_FORMAT_BGRA4444,
> >> +    DRM_FORMAT_XRGB1555,
> >> +    DRM_FORMAT_XBGR1555,
> >> +    DRM_FORMAT_RGBX5551,
> >> +    DRM_FORMAT_BGRX5551,
> >> +    DRM_FORMAT_ARGB1555,
> >> +    DRM_FORMAT_ABGR1555,
> >> +    DRM_FORMAT_RGBA5551,
> >> +    DRM_FORMAT_BGRA5551,
> >> +    DRM_FORMAT_RGB565,
> >> +    DRM_FORMAT_BGR565,
> >> +    DRM_FORMAT_XRGB8888,
> >> +    DRM_FORMAT_XBGR8888,
> >> +    DRM_FORMAT_RGBX8888,
> >> +    DRM_FORMAT_BGRX8888,
> >> +    DRM_FORMAT_ARGB8888,
> >> +    DRM_FORMAT_ABGR8888,
> >> +    DRM_FORMAT_RGBA8888,
> >> +    DRM_FORMAT_BGRA8888,
> >> +    DRM_FORMAT_ARGB2101010,
> >> +    DRM_FORMAT_ABGR2101010,
> >> +    DRM_FORMAT_RGBA1010102,
> >> +    DRM_FORMAT_BGRA1010102,
> >> +    DRM_FORMAT_YUYV,
> >> +    DRM_FORMAT_YVYU,
> >> +    DRM_FORMAT_UYVY,
> >> +    DRM_FORMAT_VYUY,
> >> +    DRM_FORMAT_YVU420,
> >> +    DRM_FORMAT_YUV420,
> >> +    DRM_FORMAT_NV12,
> >> +    DRM_FORMAT_NV21,
> >> +    DRM_FORMAT_NV16,
> >> +    DRM_FORMAT_NV61,
> >> +    DRM_FORMAT_P010,
> >> +};
> >> +
> >> +static const u32 primary_overlay_format1[] = {
> >> +    DRM_FORMAT_XRGB8888,
> >> +    DRM_FORMAT_XBGR8888,
> >> +    DRM_FORMAT_RGBX8888,
> >> +    DRM_FORMAT_BGRX8888,
> >> +    DRM_FORMAT_ARGB8888,
> >> +    DRM_FORMAT_ABGR8888,
> >> +    DRM_FORMAT_RGBA8888,
> >> +    DRM_FORMAT_BGRA8888,
> >> +    DRM_FORMAT_ARGB2101010,
> >> +    DRM_FORMAT_ABGR2101010,
> >> +    DRM_FORMAT_RGBA1010102,
> >> +    DRM_FORMAT_BGRA1010102,
> >> +    DRM_FORMAT_NV12,
> >> +    DRM_FORMAT_NV21,
> >> +    DRM_FORMAT_YUV444,
> >> +};
> >> +
> >> +static const u32 cursor_formats[] = {
> >> +    DRM_FORMAT_ARGB8888
> >> +};
> >> +
> >> +static const u64 format_modifier0[] = {
> >> +    DRM_FORMAT_MOD_LINEAR,
> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X8),
> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_8X8),
> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X8),
> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X4),
> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X4),
> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_4X8),
> >> +    DRM_FORMAT_MOD_INVALID
> >> +};
> >> +
> >> +static const u64 secondary_format_modifiers[] = {
> >> +    DRM_FORMAT_MOD_LINEAR,
> >> +    DRM_FORMAT_MOD_INVALID
> >> +};
> >> +
> >> +#define FRAC_16_16(mult, div)        (((mult) << 16) / (div))
> >> +
> >> +static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {
> >> +    {
> >> +            /* DC_REV_0 */
> >> +            {
> >> +            .name                   = "Primary",
> >
> > I'd say that the indentation is strange here.
> > It might be more scalable to split a single array into per-generation
> > data structures and reference them directly from the info struct.
> >
> >> +            .id                             = PRIMARY_PLANE_0,
> >> +            .type                   = DRM_PLANE_TYPE_PRIMARY,
> >> +            .num_formats    = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats                = primary_overlay_format0,
> >> +            .num_modifiers  = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers              = format_modifier0,
> >> +            .min_width              = 0,
> >> +            .min_height             = 0,
> >> +            .max_width              = 4096,
> >> +            .max_height             = 4096,
> >> +            .rotation               = DRM_MODE_ROTATE_0 |
> >> +                                                    DRM_MODE_ROTATE_90 |
> >> +                                                    DRM_MODE_ROTATE_180 |
> >> +                                                    DRM_MODE_ROTATE_270 |
> >> +                                                    DRM_MODE_REFLECT_X |
> >> +                                                    DRM_MODE_REFLECT_Y,
> >> +            .blend_mode             = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                                    BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                                    BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 0,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name                   = "Overlay",
> >> +            .id                             = OVERLAY_PLANE_0,
> >> +            .type                   = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats    = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats                = primary_overlay_format0,
> >> +            .num_modifiers  = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers              = format_modifier0,
> >> +            .min_width              = 0,
> >> +            .min_height             = 0,
> >> +            .max_width              = 4096,
> >> +            .max_height             = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 1,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name                   = "Overlay_1",
> >> +            .id                             = OVERLAY_PLANE_1,
> >> +            .type                   = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats    = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats                = primary_overlay_format0,
> >> +            .num_modifiers  = ARRAY_SIZE(secondary_format_modifiers),
> >> +            .modifiers              = secondary_format_modifiers,
> >> +            .min_width              = 0,
> >> +            .min_height             = 0,
> >> +            .max_width              = 4096,
> >> +            .max_height             = 4096,
> >> +            .rotation               = 0,
> >> +            .blend_mode             = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                                    BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                                    BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 2,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Primary_1",
> >> +            .id                             = PRIMARY_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 3,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay_2",
> >> +            .id                             = OVERLAY_PLANE_2,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 4,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay_3",
> >> +            .id                     = OVERLAY_PLANE_3,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> >> +            .modifiers       = secondary_format_modifiers,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = 0,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 5,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Cursor",
> >> +            .id                             = CURSOR_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
> >> +            .formats         = cursor_formats,
> >> +            .num_modifiers = 0,
> >> +            .modifiers       = NULL,
> >> +            .min_width       = 32,
> >> +            .min_height  = 32,
> >> +            .max_width       = 64,
> >> +            .max_height  = 64,
> >> +            .rotation        = 0,
> >> +            .degamma_size = 0,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 255,
> >> +            .watermark       = false,
> >> +            .color_mgmt  = false,
> >> +            .roi             = false,
> >> +            },
> >> +            {
> >> +            .name            = "Cursor_1",
> >> +            .id                             = CURSOR_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
> >> +            .formats         = cursor_formats,
> >> +            .num_modifiers = 0,
> >> +            .modifiers       = NULL,
> >> +            .min_width       = 32,
> >> +            .min_height  = 32,
> >> +            .max_width       = 64,
> >> +            .max_height  = 64,
> >> +            .rotation        = 0,
> >> +            .degamma_size = 0,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 255,
> >> +            .watermark       = false,
> >> +            .color_mgmt  = false,
> >> +            .roi             = false,
> >> +            },
> >> +    },
> >> +    {
> >> +            /* DC_REV_1 */
> >> +            {
> >> +            .name            = "Primary",
> >> +            .id                             = PRIMARY_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 0,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay",
> >> +            .id                             = OVERLAY_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 1,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Primary_1",
> >> +            .id                             = PRIMARY_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 2,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay_2",
> >> +            .id                             = OVERLAY_PLANE_2,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
> >> +            .formats         = primary_overlay_format0,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 3,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Cursor",
> >> +            .id                             = CURSOR_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
> >> +            .formats         = cursor_formats,
> >> +            .num_modifiers = 0,
> >> +            .modifiers       = NULL,
> >> +            .min_width       = 32,
> >> +            .min_height  = 32,
> >> +            .max_width       = 64,
> >> +            .max_height  = 64,
> >> +            .rotation        = 0,
> >> +            .degamma_size = 0,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 255,
> >> +            .watermark       = false,
> >> +            .color_mgmt  = false,
> >> +            .roi             = false,
> >> +            },
> >> +            {
> >> +            .name            = "Cursor_1",
> >> +            .id                             = CURSOR_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
> >> +            .formats         = cursor_formats,
> >> +            .num_modifiers = 0,
> >> +            .modifiers       = NULL,
> >> +            .min_width       = 32,
> >> +            .min_height  = 32,
> >> +            .max_width       = 64,
> >> +            .max_height  = 64,
> >> +            .rotation        = 0,
> >> +            .degamma_size = 0,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 255,
> >> +            .watermark       = false,
> >> +            .color_mgmt  = false,
> >> +            .roi             = false,
> >> +            },
> >> +    },
> >> +    {
> >> +            /* DC_REV_2 */
> >> +            {
> >> +            .name            = "Primary",
> >> +            .id                             = PRIMARY_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
> >> +            .formats         = primary_overlay_format1,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 0,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay",
> >> +            .id                             = OVERLAY_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
> >> +            .formats         = primary_overlay_format1,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 1,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay_1",
> >> +            .id                             = OVERLAY_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
> >> +            .formats         = primary_overlay_format1,
> >> +            .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> >> +            .modifiers       = secondary_format_modifiers,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = 0,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 2,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Primary_1",
> >> +            .id                             = PRIMARY_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
> >> +            .formats         = primary_overlay_format1,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 3,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay_2",
> >> +            .id                             = OVERLAY_PLANE_2,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
> >> +            .formats         = primary_overlay_format1,
> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
> >> +            .modifiers       = format_modifier0,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = DRM_MODE_ROTATE_0 |
> >> +                                       DRM_MODE_ROTATE_90 |
> >> +                                       DRM_MODE_ROTATE_180 |
> >> +                                       DRM_MODE_ROTATE_270 |
> >> +                                       DRM_MODE_REFLECT_X |
> >> +                                       DRM_MODE_REFLECT_Y,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = FRAC_16_16(1, 3),
> >> +            .max_scale       = FRAC_16_16(10, 1),
> >> +            .zpos            = 4,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Overlay_3",
> >> +            .id                             = OVERLAY_PLANE_3,
> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
> >> +            .formats         = primary_overlay_format1,
> >> +            .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
> >> +            .modifiers       = secondary_format_modifiers,
> >> +            .min_width       = 0,
> >> +            .min_height  = 0,
> >> +            .max_width       = 4096,
> >> +            .max_height  = 4096,
> >> +            .rotation        = 0,
> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
> >> +            .degamma_size   = DEGAMMA_SIZE,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 5,
> >> +            .watermark       = true,
> >> +            .color_mgmt  = true,
> >> +            .roi             = true,
> >> +            },
> >> +            {
> >> +            .name            = "Cursor",
> >> +            .id                             = CURSOR_PLANE_0,
> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
> >> +            .formats         = cursor_formats,
> >> +            .num_modifiers = 0,
> >> +            .modifiers       = NULL,
> >> +            .min_width       = 32,
> >> +            .min_height  = 32,
> >> +            .max_width       = 64,
> >> +            .max_height  = 64,
> >> +            .rotation        = 0,
> >> +            .degamma_size = 0,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 255,
> >> +            .watermark       = false,
> >> +            .color_mgmt  = false,
> >> +            .roi             = false,
> >> +            },
> >> +            {
> >> +            .name            = "Cursor_1",
> >> +            .id                             = CURSOR_PLANE_1,
> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
> >> +            .formats         = cursor_formats,
> >> +            .num_modifiers = 0,
> >> +            .modifiers       = NULL,
> >> +            .min_width       = 32,
> >> +            .min_height  = 32,
> >> +            .max_width       = 64,
> >> +            .max_height  = 64,
> >> +            .rotation        = 0,
> >> +            .degamma_size = 0,
> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
> >> +            .zpos            = 255,
> >> +            .watermark       = false,
> >> +            .color_mgmt  = false,
> >> +            .roi             = false,
> >> +            },
> >> +    },
> >> +};
> >> +
> >> +static const struct vs_dc_info dc_info[] = {
> >
> > Again, please split into per-generation instances.
> >
> >> +    {
> >> +            /* DC_REV_0 */
> >> +            .name                   = "DC8200",
> >> +            .panel_num              = 2,
> >> +            .plane_num              = 8,
> >> +            .planes                 = dc_hw_planes[DC_REV_0],
> >> +            .layer_num              = 6,
> >> +            .max_bpc                = 10,
> >> +            .color_formats  = DRM_COLOR_FORMAT_RGB444 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR444 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR422 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR420,
> >> +            .gamma_size             = GAMMA_EX_SIZE,
> >> +            .gamma_bits             = 12,
> >> +            .pitch_alignment        = 128,
> >> +            .pipe_sync              = false,
> >> +            .background             = true,
> >> +            .panel_sync             = true,
> >> +            .cap_dec                = true,
> >> +    },
> >> +    {
> >> +            /* DC_REV_1 */
> >> +            .name                   = "DC8200",
> >> +            .panel_num              = 2,
> >> +            .plane_num              = 6,
> >> +            .planes                 = dc_hw_planes[DC_REV_1],
> >> +            .layer_num              = 4,
> >> +            .max_bpc                = 10,
> >> +            .color_formats  = DRM_COLOR_FORMAT_RGB444 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR444 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR422 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR420,
> >> +            .gamma_size             = GAMMA_EX_SIZE,
> >> +            .gamma_bits             = 12,
> >> +            .pitch_alignment        = 128,
> >> +            .pipe_sync              = false,
> >> +            .background             = true,
> >> +            .panel_sync             = true,
> >> +            .cap_dec                = true,
> >> +    },
> >> +    {
> >> +            /* DC_REV_2 */
> >> +            .name                   = "DC8200",
> >> +            .panel_num              = 2,
> >> +            .plane_num              = 8,
> >> +            .planes                 = dc_hw_planes[DC_REV_2],
> >> +            .layer_num              = 6,
> >> +            .max_bpc                = 10,
> >> +            .color_formats  = DRM_COLOR_FORMAT_RGB444 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR444 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR422 |
> >> +                                              DRM_COLOR_FORMAT_YCBCR420,
> >> +            .gamma_size             = GAMMA_EX_SIZE,
> >> +            .gamma_bits             = 12,
> >> +            .pitch_alignment        = 128,
> >> +            .pipe_sync              = false,
> >> +            .background             = true,
> >> +            .panel_sync             = true,
> >> +            .cap_dec                = false,
> >> +    },
> >> +};
> >> +
> >> +static const struct dc_hw_funcs hw_func;
> >> +
> >> +static inline u32 hi_read(struct dc_hw *hw, u32 reg)
> >> +{
> >> +    return readl(hw->hi_base + reg);
> >> +}
> >> +
> >> +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
> >> +{
> >> +    writel(value, hw->hi_base + reg);
> >> +}
> >> +
> >> +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
> >> +{
> >> +    writel(value, hw->reg_base + reg - DC_REG_BASE);
> >> +}
> >> +
> >> +static inline u32 dc_read(struct dc_hw *hw, u32 reg)
> >> +{
> >> +    u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
> >> +
> >> +    return value;
> >> +}
> >> +
> >> +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
> >> +{
> >> +    u32 value = dc_read(hw, reg);
> >> +
> >> +    value &= ~clear;
> >> +    value |= set;
> >> +    dc_write(hw, reg, value);
> >> +}
> >> +
> >> +static void load_default_filter(struct dc_hw *hw,
> >> +                            const struct dc_hw_plane_reg *reg, u32 offset)
> >> +{
> >> +    u8 i;
> >> +
> >> +    dc_write(hw, reg->scale_config + offset, 0x33);
> >> +    dc_write(hw, reg->init_offset + offset, 0x80008000);
> >> +    dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
> >> +    for (i = 0; i < H_COEF_SIZE; i++)
> >> +            dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
> >> +
> >> +    dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
> >> +    for (i = 0; i < V_COEF_SIZE; i++)
> >> +            dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
> >> +}
> >> +
> >> +static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
> >> +                        u32 offset, u16 *table)
> >> +{
> >> +    dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
> >> +    dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
> >> +    dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
> >> +    dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
> >> +    dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
> >> +}
> >> +
> >> +static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
> >> +                        u32 offset, s32 *table)
> >> +{
> >> +    dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
> >> +             (0xFFFF & table[0]) | (table[1] << 16));
> >> +    dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
> >> +             (0xFFFF & table[2]) | (table[3] << 16));
> >> +    dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
> >> +             (0xFFFF & table[4]) | (table[5] << 16));
> >> +    dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
> >> +             (0xFFFF & table[6]) | (table[7] << 16));
> >> +    dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
> >> +    dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
> >> +    dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
> >> +    dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
> >> +    dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
> >> +    dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
> >> +}
> >> +
> >> +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
> >> +{
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
> >> +             table[0] | (table[1] << 16));
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
> >> +             table[2] | (table[3] << 16));
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
> >> +             table[4] | (table[5] << 16));
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
> >> +             table[6] | (table[7] << 16));
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
> >> +}
> >> +
> >> +static bool is_rgb(enum dc_hw_color_format format)
> >> +{
> >> +    switch (format) {
> >> +    case FORMAT_X4R4G4B4:
> >> +    case FORMAT_A4R4G4B4:
> >> +    case FORMAT_X1R5G5B5:
> >> +    case FORMAT_A1R5G5B5:
> >> +    case FORMAT_R5G6B5:
> >> +    case FORMAT_X8R8G8B8:
> >> +    case FORMAT_A8R8G8B8:
> >> +    case FORMAT_A2R10G10B10:
> >> +            return true;
> >> +    default:
> >> +            return false;
> >> +    }
> >> +}
> >> +
> >> +static void load_degamma_table(struct dc_hw *hw,
> >> +                           const struct dc_hw_plane_reg *reg,
> >> +                           u32 offset, u16 *table)
> >> +{
> >> +    u16 i;
> >> +    u32 value;
> >> +
> >> +    dc_write(hw, reg->degamma_index + offset, 0);
> >> +
> >> +    for (i = 0; i < DEGAMMA_SIZE; i++) {
> >> +            value = table[i] | (table[i] << 16);
> >> +            dc_write(hw, reg->degamma_data + offset, value);
> >> +            dc_write(hw, reg->degamma_ex_data + offset, table[i]);
> >> +    }
> >> +}
> >> +
> >> +static u32 get_addr_offset(u32 id)
> >> +{
> >> +    u32 offset = 0;
> >> +
> >> +    switch (id) {
> >> +    case PRIMARY_PLANE_1:
> >> +    case OVERLAY_PLANE_1:
> >> +            offset = 0x04;
> >> +            break;
> >> +    case OVERLAY_PLANE_2:
> >> +            offset = 0x08;
> >> +            break;
> >> +    case OVERLAY_PLANE_3:
> >> +            offset = 0x0C;
> >> +            break;
> >> +    default:
> >> +            break;
> >> +    }
> >> +
> >> +    return offset;
> >> +}
> >> +
> >> +int dc_hw_init(struct dc_hw *hw)
> >> +{
> >> +    u8 i, id, panel_num, layer_num;
> >> +    u32 offset;
> >> +    u32 revision = hi_read(hw, DC_HW_REVISION);
> >> +    u32 cid = hi_read(hw, DC_HW_CHIP_CID);
> >> +    const struct dc_hw_plane_reg *reg;
> >> +
> >> +    switch (revision) {
> >> +    case 0x5720:
> >> +            hw->rev = DC_REV_0;
> >> +            break;
> >> +    case 0x5721:
> >> +            switch (cid) {
> >> +            case 0x30B:
> >> +                    hw->rev = DC_REV_1;
> >> +                    break;
> >> +            case 0x310:
> >> +                    hw->rev = DC_REV_2;
> >> +                    break;
> >> +            default:
> >> +                    hw->rev = DC_REV_0;
> >> +                    break;
> >> +            }
> >> +            break;
> >> +    default:
> >> +            return -ENXIO;
> >> +    }
> >
> > We (drm/msm) had code like this for a while (and autodetection of the HW
> > ID). And nowadays we are migrating to of_device_get_match_data and
> > per-SoC compat names. It is just easier to handle, it allows one to
> > specify device more precisely and also it simplifies DT schema.
> >
> >> +
> >> +    hw->info = (struct vs_dc_info *)&dc_info[hw->rev];
> >> +    hw->func = (struct dc_hw_funcs *)&hw_func;
> >> +
> >> +    layer_num = hw->info->layer_num;
> >> +    for (i = 0; i < layer_num; i++) {
> >> +            id = hw->info->planes[i].id;
> >> +            offset = get_addr_offset(id);
> >> +            if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> >> +                    reg = &dc_plane_reg[0];
> >> +            else
> >> +                    reg = &dc_plane_reg[1];
> >> +
> >> +            load_default_filter(hw, reg, offset);
> >> +            load_rgb_to_rgb(hw, reg, offset, RGB2RGB);
> >> +    }
> >> +
> >> +    panel_num = hw->info->panel_num;
> >> +    for (i = 0; i < panel_num; i++) {
> >> +            offset = i << 2;
> >> +
> >> +            load_rgb_to_yuv(hw, offset, RGB2YUV);
> >> +            dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
> >> +
> >> +            offset = i ? DC_CURSOR_OFFSET : 0;
> >> +            dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
> >> +            dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +void dc_hw_deinit(struct dc_hw *hw)
> >> +{
> >> +    /* Nothing to do */
> >> +}
> >> +
> >> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
> >> +                    struct dc_hw_fb *fb, struct dc_hw_scale *scale,
> >> +                    struct dc_hw_position *pos, struct dc_hw_blend *blend)
> >> +{
> >> +    struct dc_hw_plane *plane = &hw->plane[id];
> >> +
> >> +    if (plane) {
> >> +            if (fb) {
> >> +                    if (!fb->enable)
> >> +                            plane->fb.enable = false;
> >> +                    else
> >> +                            memcpy(&plane->fb, fb,
> >> +                                   sizeof(*fb) - sizeof(fb->dirty));
> >> +                    plane->fb.dirty = true;
> >> +            }
> >> +            if (scale) {
> >> +                    memcpy(&plane->scale, scale,
> >> +                           sizeof(*scale) - sizeof(scale->dirty));
> >> +                    plane->scale.dirty = true;
> >> +            }
> >> +            if (pos) {
> >> +                    memcpy(&plane->pos, pos,
> >> +                           sizeof(*pos) - sizeof(pos->dirty));
> >> +                    plane->pos.dirty = true;
> >> +            }
> >> +            if (blend) {
> >> +                    memcpy(&plane->blend, blend,
> >> +                           sizeof(*blend) - sizeof(blend->dirty));
> >> +                    plane->blend.dirty = true;
> >> +            }
> >> +    }
> >> +}
> >> +
> >> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode)
> >> +{
> >> +    struct dc_hw_plane *plane = &hw->plane[id];
> >> +
> >> +    if (plane) {
> >> +            if (hw->info->planes[id].degamma_size) {
> >> +                    plane->degamma.mode = mode;
> >> +                    plane->degamma.dirty = true;
> >> +            } else {
> >> +                    plane->degamma.dirty = false;
> >> +            }
> >> +    }
> >> +}
> >> +
> >> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi)
> >> +{
> >> +    struct dc_hw_plane *plane = &hw->plane[id];
> >> +
> >> +    if (plane) {
> >> +            memcpy(&plane->roi, roi, sizeof(*roi) - sizeof(roi->dirty));
> >> +            plane->roi.dirty = true;
> >> +    }
> >> +}
> >> +
> >> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
> >> +                       struct dc_hw_colorkey *colorkey)
> >> +{
> >> +    struct dc_hw_plane *plane = &hw->plane[id];
> >> +
> >> +    if (plane) {
> >> +            memcpy(&plane->colorkey, colorkey,
> >> +                   sizeof(*colorkey) - sizeof(colorkey->dirty));
> >> +            plane->colorkey.dirty = true;
> >> +    }
> >> +}
> >> +
> >> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos)
> >> +{
> >> +    memcpy(&hw->qos, qos, sizeof(*qos) - sizeof(qos->dirty));
> >> +    hw->qos.dirty = true;
> >> +}
> >> +
> >> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor)
> >> +{
> >> +    memcpy(&hw->cursor[id], cursor, sizeof(*cursor) - sizeof(cursor->dirty));
> >> +    hw->cursor[id].dirty = true;
> >> +}
> >> +
> >> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> >> +                    u16 r, u16 g, u16 b)
> >> +{
> >> +    if (index >= hw->info->gamma_size)
> >> +            return;
> >> +
> >> +    hw->gamma[id].gamma[index][0] = r;
> >> +    hw->gamma[id].gamma[index][1] = g;
> >> +    hw->gamma[id].gamma[index][2] = b;
> >> +    hw->gamma[id].dirty = true;
> >> +}
> >> +
> >> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
> >> +{
> >> +    hw->gamma[id].enable = enable;
> >> +    hw->gamma[id].dirty = true;
> >> +}
> >> +
> >> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display)
> >> +{
> >> +    u8 id = display->id;
> >> +
> >> +    memcpy(&hw->display[id], display, sizeof(*display));
> >> +
> >> +    hw->func->display(hw, display);
> >> +}
> >> +
> >> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable)
> >> +{
> >> +    if (enable)
> >> +            hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
> >> +    else
> >> +            hi_write(hw, AQ_INTR_ENBL, 0);
> >> +}
> >> +
> >> +u32 dc_hw_get_interrupt(struct dc_hw *hw)
> >> +{
> >> +    return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
> >> +}
> >> +
> >> +bool dc_hw_check_underflow(struct dc_hw *hw)
> >> +{
> >> +    return dc_read(hw, DC_FRAMEBUFFER_CONFIG) & BIT(5);
> >> +}
> >> +
> >> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable)
> >> +{
> >> +    u32 i, offset;
> >> +    u8 id, layer_num = hw->info->layer_num;
> >> +    u8 panel_num = hw->info->panel_num;
> >> +
> >> +    for (i = 0; i < layer_num; i++) {
> >> +            id = hw->info->planes[i].id;
> >> +            offset = get_addr_offset(id);
> >> +            if (enable) {
> >> +                    if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, BIT(12), 0);
> >> +                    else
> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, BIT(31), 0);
> >> +            } else {
> >> +                    if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, 0, BIT(12));
> >> +                    else
> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, 0, BIT(31));
> >> +            }
> >> +    }
> >> +
> >> +    for (i = 0; i < panel_num; i++) {
> >> +            offset = i << 2;
> >> +            if (enable)
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, BIT(0));
> >> +            else
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, BIT(0), 0);
> >> +    }
> >> +}
> >> +
> >> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
> >> +{
> >> +    if (out <= OUT_DP)
> >> +            hw->out[id] = out;
> >> +}
> >> +
> >> +static void gamma_ex_commit(struct dc_hw *hw)
> >> +{
> >> +    u8 panel_num = hw->info->panel_num;
> >> +    u16 i, j;
> >> +    u32 value;
> >> +
> >> +    for (j = 0; j < panel_num; j++) {
> >> +            if (hw->gamma[j].dirty) {
> >> +                    if (hw->gamma[j].enable) {
> >> +                            dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (j << 2), 0x00);
> >> +                            for (i = 0; i < GAMMA_EX_SIZE; i++) {
> >> +                                    value = hw->gamma[j].gamma[i][2] |
> >> +                                            (hw->gamma[j].gamma[i][1] << 12);
> >> +                                    dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (j << 2), value);
> >> +                                    dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (j << 2),
> >> +                                             hw->gamma[j].gamma[i][0]);
> >> +                            }
> >> +                            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
> >> +                                         BIT(13), 0);
> >> +                    } else {
> >> +                            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
> >> +                                         0, BIT(13));
> >> +                    }
> >> +                    hw->gamma[j].dirty = false;
> >> +            }
> >> +    }
> >> +}
> >> +
> >> +static void plane_commit(struct dc_hw *hw)
> >> +{
> >> +    struct dc_hw_plane *plane;
> >> +    const struct dc_hw_plane_reg *reg;
> >> +    bool primary = false;
> >> +    u8 id, layer_num = hw->info->layer_num;
> >> +    u32 i, offset;
> >> +
> >> +    for (i = 0; i < layer_num; i++) {
> >> +            plane = &hw->plane[i];
> >> +            id = hw->info->planes[i].id;
> >> +            offset = get_addr_offset(id);
> >> +            if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
> >> +                    reg = &dc_plane_reg[0];
> >> +                    primary = true;
> >> +            } else {
> >> +                    reg = &dc_plane_reg[1];
> >> +                    primary = false;
> >> +            }
> >
> > Can you please move register defines to some internal hw_plane
> > structure. These details are known at the time of creation of the plane.
> > There is no need to determine them again and again.
> >
> >> +
> >> +            if (plane->fb.dirty) {
> >> +                    if (plane->fb.enable) {
> >
> > if (plane->fb.dirty && plane->fb.enable) will save you one level of
> > indentation.
> >
> > However it might be better to use existing DRM flags instead of
> > inventing your own flags.
> >
> >> +                            dc_write(hw, reg->y_address + offset,
> >> +                                     plane->fb.y_address);
> >> +                            dc_write(hw, reg->u_address + offset,
> >> +                                     plane->fb.u_address);
> >> +                            dc_write(hw, reg->v_address + offset,
> >> +                                     plane->fb.v_address);
> >> +                            dc_write(hw, reg->y_stride + offset,
> >> +                                     plane->fb.y_stride);
> >> +                            dc_write(hw, reg->u_stride + offset,
> >> +                                     plane->fb.u_stride);
> >> +                            dc_write(hw, reg->v_stride + offset,
> >> +                                     plane->fb.v_stride);
> >> +                            dc_write(hw, reg->size + offset,
> >> +                                     plane->fb.width |
> >> +                                     (plane->fb.height << 15));
> >> +                            dc_write(hw, reg->water_mark + offset,
> >> +                                     plane->fb.water_mark);
> >> +
> >> +                            if (plane->fb.clear_enable)
> >> +                                    dc_write(hw, reg->clear_value + offset,
> >> +                                             plane->fb.clear_value);
> >> +                    }
> >> +
> >> +                    if (primary) {
> >
> > You have two kinds of planes. Primary and overlays. Could you please
> > split this code into two separate functions and define two vtables, one
> > for primary planes and one for overlays. There is no need to stick
> > everything into a single funcion that handles everything.
> >
> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> >> +                                         (plane->fb.format << 26) |
> >> +                                         (plane->fb.uv_swizzle << 25) |
> >> +                                         (plane->fb.swizzle << 23) |
> >> +                                         (plane->fb.tile_mode << 17) |
> >> +                                         (plane->fb.yuv_color_space << 14) |
> >> +                                         (plane->fb.rotation << 11) |
> >> +                                         (plane->fb.clear_enable << 8),
> >> +                                         (0x1F << 26) |
> >> +                                         BIT(25) |
> >> +                                         (0x03 << 23) |
> >> +                                         (0x1F << 17) |
> >> +                                         (0x07 << 14) |
> >> +                                         (0x07 << 11) |
> >> +                                         BIT(8));
> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                         (plane->fb.dec_enable << 1) |
> >> +                                         (plane->fb.enable << 13) |
> >> +                                         (plane->fb.zpos << 16) |
> >> +                                         (plane->fb.display_id << 19),
> >> +                                         BIT(1) | BIT(13) | (0x07 << 16) | BIT(19));
> >
> > It looks like this code can enjoy defining names for all the magic
> > values. Otherwise it is impossible to support it.
> >
> >> +                    } else {
> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> >> +                                         (plane->fb.dec_enable << 27) |
> >> +                                         (plane->fb.clear_enable << 25) |
> >> +                                         (plane->fb.enable << 24) |
> >> +                                         (plane->fb.format << 16) |
> >> +                                         (plane->fb.uv_swizzle << 15) |
> >> +                                         (plane->fb.swizzle << 13) |
> >> +                                         (plane->fb.tile_mode << 8) |
> >> +                                         (plane->fb.yuv_color_space << 5) |
> >> +                                         (plane->fb.rotation << 2),
> >> +                                         BIT(27) |
> >> +                                         BIT(25) |
> >> +                                         BIT(24) |
> >> +                                         (0x1F << 16) |
> >> +                                         BIT(15) |
> >> +                                         (0x03 << 13) |
> >> +                                         (0x1F << 8) |
> >> +                                         (0x07 << 5) |
> >> +                                         (0x07 << 2));
> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
> >> +                                         plane->fb.zpos | (plane->fb.display_id << 3),
> >> +                                         0x07 | BIT(3));
> >> +                    }
> >> +                    plane->fb.dirty = false;
> >> +            }
> >> +
> >> +            if (plane->scale.dirty) {
> >> +                    if (plane->scale.enable) {
> >> +                            dc_write(hw, reg->scale_factor_x + offset,
> >> +                                     plane->scale.scale_factor_x);
> >> +                            dc_write(hw, reg->scale_factor_y + offset,
> >> +                                     plane->scale.scale_factor_y);
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG + offset,
> >> +                                                 BIT(22), 0);
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_SCALE_CONFIG + offset,
> >> +                                                 BIT(8), 0);
> >> +                    } else {
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG + offset,
> >> +                                                 0, BIT(22));
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_SCALE_CONFIG + offset,
> >> +                                                 0, BIT(8));
> >> +                    }
> >> +                    plane->scale.dirty = false;
> >> +            }
> >> +
> >> +            if (plane->pos.dirty) {
> >> +                    dc_write(hw, reg->top_left + offset,
> >> +                             plane->pos.start_x |
> >> +                             (plane->pos.start_y << 15));
> >> +                    dc_write(hw, reg->bottom_right + offset,
> >> +                             plane->pos.end_x |
> >> +                             (plane->pos.end_y << 15));
> >> +                    plane->pos.dirty = false;
> >> +            }
> >> +
> >> +            if (plane->blend.dirty) {
> >> +                    dc_write(hw, reg->src_global_color + offset,
> >> +                             plane->blend.alpha << 24);
> >> +                    dc_write(hw, reg->dst_global_color + offset,
> >> +                             plane->blend.alpha << 24);
> >> +                    switch (plane->blend.blend_mode) {
> >> +                    case BLEND_PREMULTI:
> >> +                            dc_write(hw, reg->blend_config + offset, 0x3450);
> >> +                            break;
> >> +                    case BLEND_COVERAGE:
> >> +                            dc_write(hw, reg->blend_config + offset, 0x3950);
> >> +                            break;
> >> +                    case BLEND_PIXEL_NONE:
> >> +                            dc_write(hw, reg->blend_config + offset, 0x3548);
> >> +                            break;
> >> +                    default:
> >> +                            break;
> >> +                    }
> >> +                    plane->blend.dirty = false;
> >> +            }
> >> +
> >> +            if (plane->colorkey.dirty) {
> >> +                    dc_write(hw, reg->color_key + offset, plane->colorkey.colorkey);
> >> +                    dc_write(hw, reg->color_key_high + offset,
> >> +                             plane->colorkey.colorkey_high);
> >> +
> >> +                    if (primary)
> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
> >> +                                         plane->colorkey.transparency << 9, 0x03 << 9);
> >> +                    else
> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> >> +                                         plane->colorkey.transparency, 0x03);
> >> +
> >> +                    plane->colorkey.dirty = false;
> >> +            }
> >> +
> >> +            if (plane->roi.dirty) {
> >> +                    if (plane->roi.enable) {
> >> +                            dc_write(hw, reg->roi_origin + offset,
> >> +                                     plane->roi.x | (plane->roi.y << 16));
> >> +                            dc_write(hw, reg->roi_size + offset,
> >> +                                     plane->roi.width | (plane->roi.height << 16));
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 BIT(0), 0);
> >> +                            else
> >> +                                    dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> >> +                                                 BIT(22), 0);
> >> +                    } else {
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 0, BIT(0));
> >> +                            else
> >> +                                    dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
> >> +                                                 0, BIT(22));
> >> +                    }
> >> +                    plane->roi.dirty = false;
> >> +            }
> >> +    }
> >> +}
> >> +
> >> +static void plane_ex_commit(struct dc_hw *hw)
> >> +{
> >> +    struct dc_hw_plane *plane;
> >> +    const struct dc_hw_plane_reg *reg;
> >> +    bool primary = false;
> >> +    u8 id, layer_num = hw->info->layer_num;
> >> +    u32 i, offset;
> >> +
> >> +    for (i = 0; i < layer_num; i++) {
> >> +            plane = &hw->plane[i];
> >> +            id = hw->info->planes[i].id;
> >> +            offset = get_addr_offset(id);
> >> +            if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
> >> +                    reg = &dc_plane_reg[0];
> >> +                    primary = true;
> >> +            } else {
> >> +                    reg = &dc_plane_reg[1];
> >> +                    primary = false;
> >> +            }
> >> +
> >> +            if (plane->fb.dirty) {
> >> +                    if (is_rgb(plane->fb.format)) {
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 BIT(6), BIT(8));
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_CONFIG + offset,
> >> +                                                 BIT(29), BIT(30));
> >> +                    } else {
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 BIT(8), BIT(6));
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_CONFIG + offset,
> >> +                                                 BIT(30), BIT(29));
> >> +                            switch (plane->fb.yuv_color_space) {
> >> +                            case COLOR_SPACE_601:
> >> +                                    load_yuv_to_rgb(hw, reg, offset, YUV601_2RGB);
> >> +                                    break;
> >> +                            case COLOR_SPACE_709:
> >> +                                    load_yuv_to_rgb(hw, reg, offset, YUV709_2RGB);
> >> +                                    break;
> >> +                            case COLOR_SPACE_2020:
> >> +                                    load_yuv_to_rgb(hw, reg, offset, YUV2020_2RGB);
> >> +                                    break;
> >> +                            default:
> >> +                                    break;
> >> +                            }
> >> +                    }
> >> +            }
> >> +            if (plane->degamma.dirty) {
> >> +                    switch (plane->degamma.mode) {
> >> +                    case VS_DEGAMMA_DISABLE:
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 0, BIT(5));
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_CONFIG + offset,
> >> +                                                 0, BIT(28));
> >> +                            break;
> >> +                    case VS_DEGAMMA_BT709:
> >> +                            load_degamma_table(hw, reg, offset, DEGAMMA_709);
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 BIT(5), 0);
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_CONFIG + offset,
> >> +                                                 BIT(28), 0);
> >> +                            break;
> >> +                    case VS_DEGAMMA_BT2020:
> >> +                            load_degamma_table(hw, reg, offset, DEGAMMA_2020);
> >> +                            if (primary)
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
> >> +                                                 BIT(5), 0);
> >> +                            else
> >> +                                    dc_set_clear(hw,
> >> +                                                 DC_OVERLAY_CONFIG + offset,
> >> +                                                 BIT(28), 0);
> >> +                            break;
> >> +                    default:
> >> +                            break;
> >> +                    }
> >> +                    plane->degamma.dirty = false;
> >> +            }
> >> +    }
> >> +    plane_commit(hw);
> >> +}
> >> +
> >> +static void setup_display(struct dc_hw *hw, struct dc_hw_display *display)
> >> +{
> >> +    u8 id = display->id;
> >> +    u32 dpi_cfg, offset = id << 2;
> >> +
> >> +    if (hw->display[id].enable) {
> >> +            switch (display->bus_format) {
> >> +            case MEDIA_BUS_FMT_RGB565_1X16:
> >> +                    dpi_cfg = 0;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB666_1X18:
> >> +                    dpi_cfg = 3;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> >> +                    dpi_cfg = 4;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB888_1X24:
> >> +                    dpi_cfg = 5;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB101010_1X30:
> >> +                    dpi_cfg = 6;
> >> +                    break;
> >> +            default:
> >> +                    dpi_cfg = 5;
> >> +                    break;
> >> +            }
> >> +            dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
> >> +
> >> +            if (id == 0)
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
> >> +            else
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
> >> +
> >> +            dc_write(hw, DC_DISPLAY_H + offset, hw->display[id].h_active |
> >> +                     (hw->display[id].h_total << 16));
> >> +            dc_write(hw, DC_DISPLAY_H_SYNC + offset,
> >> +                     hw->display[id].h_sync_start |
> >> +                     (hw->display[id].h_sync_end << 15) |
> >> +                     (hw->display[id].h_sync_polarity ? 0 : BIT(31)) |
> >> +                     BIT(30));
> >> +            dc_write(hw, DC_DISPLAY_V + offset, hw->display[id].v_active |
> >> +                            (hw->display[id].v_total << 16));
> >> +            dc_write(hw, DC_DISPLAY_V_SYNC + offset,
> >> +                     hw->display[id].v_sync_start |
> >> +                     (hw->display[id].v_sync_end << 15) |
> >> +                     (hw->display[id].v_sync_polarity ? 0 : BIT(31)) |
> >> +                     BIT(30));
> >> +
> >> +            if (hw->info->pipe_sync)
> >> +                    dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
> >> +                                 0, BIT(3) | BIT(4));
> >> +
> >> +            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(12), 0);
> >> +            if (id == 0)
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(0), BIT(3));
> >> +            else
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(1), BIT(3));
> >> +    } else {
> >> +            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(12));
> >> +            if (id == 0)
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
> >> +            else
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
> >> +    }
> >> +}
> >> +
> >> +static void setup_display_ex(struct dc_hw *hw, struct dc_hw_display *display)
> >> +{
> >> +    u8 id = display->id;
> >> +    u32 dp_cfg, offset = id << 2;
> >> +    bool is_yuv = false;
> >> +
> >> +    if (hw->display[id].enable && hw->out[id] == OUT_DP) {
> >> +            switch (display->bus_format) {
> >> +            case MEDIA_BUS_FMT_RGB565_1X16:
> >> +                    dp_cfg = 0;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB666_1X18:
> >> +                    dp_cfg = 1;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB888_1X24:
> >> +                    dp_cfg = 2;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_RGB101010_1X30:
> >> +                    dp_cfg = 3;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_UYVY8_1X16:
> >> +                    dp_cfg = 2 << 4;
> >> +                    is_yuv = true;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_YUV8_1X24:
> >> +                    dp_cfg = 4 << 4;
> >> +                    is_yuv = true;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_UYVY10_1X20:
> >> +                    dp_cfg = 8 << 4;
> >> +                    is_yuv = true;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_YUV10_1X30:
> >> +                    dp_cfg = 10 << 4;
> >> +                    is_yuv = true;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> >> +                    dp_cfg = 12 << 4;
> >> +                    is_yuv = true;
> >> +                    break;
> >> +            case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> >> +                    dp_cfg = 13 << 4;
> >> +                    is_yuv = true;
> >> +                    break;
> >> +            default:
> >> +                    dp_cfg = 2;
> >> +                    break;
> >> +            }
> >> +            if (is_yuv)
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(16), 0);
> >> +            else
> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(16));
> >> +            dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | BIT(3));
> >> +    }
> >> +
> >> +    if (hw->out[id] == OUT_DPI)
> >> +            dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, BIT(3));
> >> +
> >> +    setup_display(hw, display);
> >> +}
> >> +
> >> +static const struct dc_hw_funcs hw_func = {
> >> +    .gamma = &gamma_ex_commit,
> >> +    .plane = &plane_ex_commit,
> >> +    .display = setup_display_ex,
> >> +};
> >> +
> >> +void dc_hw_commit(struct dc_hw *hw)
> >> +{
> >> +    u32 i, offset = 0;
> >> +    u8 plane_num = hw->info->plane_num;
> >> +    u8 layer_num = hw->info->layer_num;
> >> +    u8 cursor_num = plane_num - layer_num;
> >> +
> >> +    hw->func->gamma(hw);
> >> +    hw->func->plane(hw);
> >> +
> >> +    for (i = 0; i < cursor_num; i++) {
> >> +            if (hw->cursor[i].dirty) {
> >> +                    offset = hw->cursor[i].display_id ? DC_CURSOR_OFFSET : 0;
> >> +                    if (hw->cursor[i].enable) {
> >> +                            dc_write(hw, DC_CURSOR_ADDRESS + offset,
> >> +                                     hw->cursor[i].address);
> >> +                            dc_write(hw, DC_CURSOR_LOCATION + offset, hw->cursor[i].x |
> >> +                                     (hw->cursor[i].y << 16));
> >> +                            dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
> >> +                                         (hw->cursor[i].hot_x << 16) |
> >> +                                         (hw->cursor[i].hot_y << 8) |
> >> +                                         (hw->cursor[i].size << 5) |
> >> +                                         BIT(3) | BIT(2) | 0x02,
> >> +                                         (0xFF << 16) |
> >> +                                         (0xFF << 8) |
> >> +                                         (0x07 << 5) | 0x1F);
> >> +                    } else {
> >> +                            dc_set_clear(hw, DC_CURSOR_CONFIG + offset, BIT(3), 0x03);
> >> +                    }
> >> +                    hw->cursor[i].dirty = false;
> >> +            }
> >> +    }
> >> +
> >> +    if (hw->qos.dirty) {
> >> +            dc_set_clear(hw, DC_QOS_CONFIG, (hw->qos.high_value << 4) |
> >> +                                     hw->qos.low_value, 0xFF);
> >> +            hw->qos.dirty = false;
> >> +    }
> >> +}
> >> +
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> >> new file mode 100644
> >> index 000000000..9a1d767ae
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
> >> @@ -0,0 +1,492 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#ifndef __VS_DC_HW_H__
> >> +#define __VS_DC_HW_H__
> >> +
> >> +#define AQ_INTR_ACKNOWLEDGE                         0x0010
> >> +#define AQ_INTR_ENBL                                        0x0014
> >
> > Please take care to align all the defines.
> >
> >> +#define DC_HW_REVISION                                      0x0024
> >> +#define DC_HW_CHIP_CID                                      0x0030
> >> +
> >> +#define DC_REG_BASE                                         0x0800
> >> +#define DC_REG_RANGE                                        0x2000
> >> +#define DC_SEC_REG_OFFSET                           0x100000
> >> +
> >> +#define DC_FRAMEBUFFER_CONFIG                       0x1518
> >> +#define DC_FRAMEBUFFER_CONFIG_EX            0x1CC0
> >> +#define DC_FRAMEBUFFER_SCALE_CONFIG         0x1520
> >> +#define DC_FRAMEBUFFER_TOP_LEFT                     0x24D8
> >> +#define DC_FRAMEBUFFER_BOTTOM_RIGHT         0x24E0
> >> +#define DC_FRAMEBUFFER_ADDRESS                      0x1400
> >> +#define DC_FRAMEBUFFER_U_ADDRESS            0x1530
> >> +#define DC_FRAMEBUFFER_V_ADDRESS            0x1538
> >> +#define DC_FRAMEBUFFER_STRIDE                       0x1408
> >> +#define DC_FRAMEBUFFER_U_STRIDE                     0x1800
> >> +#define DC_FRAMEBUFFER_V_STRIDE                     0x1808
> >> +#define DC_FRAMEBUFFER_SIZE                         0x1810
> >> +#define DC_FRAMEBUFFER_SCALE_FACTOR_X               0x1828
> >> +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y               0x1830
> >> +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX  0x1838
> >> +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA   0x1A00
> >> +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX  0x1A08
> >> +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA   0x1A10
> >> +#define DC_FRAMEBUFFER_INIT_OFFSET                  0x1A20
> >> +#define DC_FRAMEBUFFER_COLOR_KEY                    0x1508
> >> +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH               0x1510
> >> +#define DC_FRAMEBUFFER_CLEAR_VALUE                  0x1A18
> >> +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX    0x1818
> >> +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA             0x1820
> >> +#define DC_FRAMEBUFFER_BG_COLOR                             0x1528
> >> +#define DC_FRAMEBUFFER_ROI_ORIGIN                   0x1CB0
> >> +#define DC_FRAMEBUFFER_ROI_SIZE                             0x1CB8
> >> +#define DC_FRAMEBUFFER_WATER_MARK                   0x1CE8
> >> +#define DC_FRAMEBUFFER_DEGAMMA_INDEX                0x1D88
> >> +#define DC_FRAMEBUFFER_DEGAMMA_DATA                 0x1D90
> >> +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA              0x1D98
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF0               0x1DA0
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF1               0x1DA8
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF2               0x1DB0
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF3               0x1DB8
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF4               0x1E00
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0              0x1E08
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1              0x1E10
> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2              0x1E18
> >> +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND                0x1E88
> >> +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND               0x1E90
> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF0               0x1E20
> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF1               0x1E28
> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF2               0x1E30
> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF3               0x1E38
> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF4               0x1E40
> >> +#define DC_FRAMEBUFFER_BLEND_CONFIG                 0x2510
> >> +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR             0x2500
> >> +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR             0x2508
> >> +
> >> +#define DC_OVERLAY_CONFIG                                   0x1540
> >> +#define DC_OVERLAY_CONFIG_EX                                0x2540
> >> +#define DC_OVERLAY_SCALE_CONFIG                             0x1C00
> >> +#define DC_OVERLAY_BLEND_CONFIG                             0x1580
> >> +#define DC_OVERLAY_TOP_LEFT                                 0x1640
> >> +#define DC_OVERLAY_BOTTOM_RIGHT                             0x1680
> >> +#define DC_OVERLAY_ADDRESS                                  0x15C0
> >> +#define DC_OVERLAY_U_ADDRESS                                0x1840
> >> +#define DC_OVERLAY_V_ADDRESS                                0x1880
> >> +#define DC_OVERLAY_STRIDE                                   0x1600
> >> +#define DC_OVERLAY_U_STRIDE                                 0x18C0
> >> +#define DC_OVERLAY_V_STRIDE                                 0x1900
> >> +#define DC_OVERLAY_SIZE                                             0x17C0
> >> +#define DC_OVERLAY_SCALE_FACTOR_X                   0x1A40
> >> +#define DC_OVERLAY_SCALE_FACTOR_Y                   0x1A80
> >> +#define DC_OVERLAY_H_FILTER_COEF_INDEX              0x1AC0
> >> +#define DC_OVERLAY_H_FILTER_COEF_DATA               0x1B00
> >> +#define DC_OVERLAY_V_FILTER_COEF_INDEX              0x1B40
> >> +#define DC_OVERLAY_V_FILTER_COEF_DATA               0x1B80
> >> +#define DC_OVERLAY_INIT_OFFSET                              0x1BC0
> >> +#define DC_OVERLAY_COLOR_KEY                                0x1740
> >> +#define DC_OVERLAY_COLOR_KEY_HIGH                   0x1780
> >> +#define DC_OVERLAY_CLEAR_VALUE                              0x1940
> >> +#define DC_OVERLAY_COLOR_TABLE_INDEX                0x1980
> >> +#define DC_OVERLAY_COLOR_TABLE_DATA                 0x19C0
> >> +#define DC_OVERLAY_SRC_GLOBAL_COLOR                 0x16C0
> >> +#define DC_OVERLAY_DST_GLOBAL_COLOR                 0x1700
> >> +#define DC_OVERLAY_ROI_ORIGIN                               0x1D00
> >> +#define DC_OVERLAY_ROI_SIZE                                 0x1D40
> >> +#define DC_OVERLAY_WATER_MARK                               0x1DC0
> >> +#define DC_OVERLAY_DEGAMMA_INDEX                    0x2200
> >> +#define DC_OVERLAY_DEGAMMA_DATA                             0x2240
> >> +#define DC_OVERLAY_DEGAMMA_EX_DATA                  0x2280
> >> +#define DC_OVERLAY_YUVTORGB_COEF0                   0x1EC0
> >> +#define DC_OVERLAY_YUVTORGB_COEF1                   0x1F00
> >> +#define DC_OVERLAY_YUVTORGB_COEF2                   0x1F40
> >> +#define DC_OVERLAY_YUVTORGB_COEF3                   0x1F80
> >> +#define DC_OVERLAY_YUVTORGB_COEF4                   0x1FC0
> >> +#define DC_OVERLAY_YUVTORGB_COEFD0                  0x2000
> >> +#define DC_OVERLAY_YUVTORGB_COEFD1                  0x2040
> >> +#define DC_OVERLAY_YUVTORGB_COEFD2                  0x2080
> >> +#define DC_OVERLAY_Y_CLAMP_BOUND                    0x22C0
> >> +#define DC_OVERLAY_UV_CLAMP_BOUND                   0x2300
> >> +#define DC_OVERLAY_RGBTORGB_COEF0                   0x20C0
> >> +#define DC_OVERLAY_RGBTORGB_COEF1                   0x2100
> >> +#define DC_OVERLAY_RGBTORGB_COEF2                   0x2140
> >> +#define DC_OVERLAY_RGBTORGB_COEF3                   0x2180
> >> +#define DC_OVERLAY_RGBTORGB_COEF4                   0x21C0
> >> +
> >> +#define DC_CURSOR_CONFIG                                    0x1468
> >> +#define DC_CURSOR_ADDRESS                                   0x146C
> >> +#define DC_CURSOR_LOCATION                                  0x1470
> >> +#define DC_CURSOR_BACKGROUND                                0x1474
> >> +#define DC_CURSOR_FOREGROUND                                0x1478
> >> +#define DC_CURSOR_CLK_GATING                                0x1484
> >> +#define DC_CURSOR_CONFIG_EX                                 0x24E8
> >> +#define DC_CURSOR_OFFSET                                    0x1080
> >> +
> >> +#define DC_DISPLAY_DITHER_CONFIG            0x1410
> >> +#define DC_DISPLAY_PANEL_CONFIG                     0x1418
> >> +#define DC_DISPLAY_PANEL_CONFIG_EX          0x2518
> >> +#define DC_DISPLAY_DITHER_TABLE_LOW         0x1420
> >> +#define DC_DISPLAY_DITHER_TABLE_HIGH        0x1428
> >> +#define DC_DISPLAY_H                                        0x1430
> >> +#define DC_DISPLAY_H_SYNC                           0x1438
> >> +#define DC_DISPLAY_V                                        0x1440
> >> +#define DC_DISPLAY_V_SYNC                           0x1448
> >> +#define DC_DISPLAY_CURRENT_LOCATION         0x1450
> >> +#define DC_DISPLAY_GAMMA_INDEX                      0x1458
> >> +#define DC_DISPLAY_GAMMA_DATA                       0x1460
> >> +#define DC_DISPLAY_INT                                      0x147C
> >> +#define DC_DISPLAY_INT_ENABLE                       0x1480
> >> +#define DC_DISPLAY_DBI_CONFIG                       0x1488
> >> +#define DC_DISPLAY_GENERAL_CONFIG           0x14B0
> >> +#define DC_DISPLAY_DPI_CONFIG                       0x14B8
> >> +#define DC_DISPLAY_PANEL_START                      0x1CCC
> >> +#define DC_DISPLAY_DEBUG_COUNTER_SELECT             0x14D0
> >> +#define DC_DISPLAY_DEBUG_COUNTER_VALUE              0x14D8
> >> +#define DC_DISPLAY_DP_CONFIG                                0x1CD0
> >> +#define DC_DISPLAY_GAMMA_EX_INDEX                   0x1CF0
> >> +#define DC_DISPLAY_GAMMA_EX_DATA                    0x1CF8
> >> +#define DC_DISPLAY_GAMMA_EX_ONE_DATA                0x1D80
> >> +#define DC_DISPLAY_RGBTOYUV_COEF0                   0x1E48
> >> +#define DC_DISPLAY_RGBTOYUV_COEF1                   0x1E50
> >> +#define DC_DISPLAY_RGBTOYUV_COEF2                   0x1E58
> >> +#define DC_DISPLAY_RGBTOYUV_COEF3                   0x1E60
> >> +#define DC_DISPLAY_RGBTOYUV_COEF4                   0x1E68
> >> +#define DC_DISPLAY_RGBTOYUV_COEFD0                  0x1E70
> >> +#define DC_DISPLAY_RGBTOYUV_COEFD1                  0x1E78
> >> +#define DC_DISPLAY_RGBTOYUV_COEFD2                  0x1E80
> >> +
> >> +#define DC_CLK_GATTING                                      0x1A28
> >> +#define DC_QOS_CONFIG                                       0x1A38
> >> +
> >> +#define DC_TRANSPARENCY_OPAQUE                      0x00
> >> +#define DC_TRANSPARENCY_KEY                         0x02
> >> +#define DC_DISPLAY_DITHERTABLE_LOW          0x7B48F3C0
> >> +#define DC_DISPLAY_DITHERTABLE_HIGH         0x596AD1E2
> >> +
> >> +#define GAMMA_SIZE                                          256
> >> +#define GAMMA_EX_SIZE                                       300
> >> +#define DEGAMMA_SIZE                                        260
> >> +
> >> +#define RGB_TO_RGB_TABLE_SIZE                       9
> >> +#define YUV_TO_RGB_TABLE_SIZE                       16
> >> +#define RGB_TO_YUV_TABLE_SIZE                       12
> >> +
> >> +#define DC_LAYER_NUM        6
> >> +#define DC_DISPLAY_NUM      2
> >> +#define DC_CURSOR_NUM       2
> >> +
> >> +#define DC_TILE_MODE4X4     0x15
> >> +
> >> +enum dc_chip_rev {
> >> +    DC_REV_0,/* For HW_REV_5720,HW_REV_5721_311 */
> >> +    DC_REV_1,/* For HW_REV_5721_30B */
> >> +    DC_REV_2,/* For HW_REV_5721_310 */
> >> +};
> >> +
> >> +enum dc_hw_plane_id {
> >> +    PRIMARY_PLANE_0,
> >> +    OVERLAY_PLANE_0,
> >> +    OVERLAY_PLANE_1,
> >> +    PRIMARY_PLANE_1,
> >> +    OVERLAY_PLANE_2,
> >> +    OVERLAY_PLANE_3,
> >> +    CURSOR_PLANE_0,
> >> +    CURSOR_PLANE_1,
> >> +    PLANE_NUM
> >> +};
> >> +
> >> +enum dc_hw_color_format {
> >> +    FORMAT_X4R4G4B4,//0
> >
> > Space after the comma will make it more readable. Or just define the
> > values explicitly, it will also be more readable.
> >
> >> +    FORMAT_A4R4G4B4,//1
> >> +    FORMAT_X1R5G5B5,//2
> >> +    FORMAT_A1R5G5B5,//3
> >> +    FORMAT_R5G6B5,//4
> >> +    FORMAT_X8R8G8B8,//5
> >> +    FORMAT_A8R8G8B8,//6
> >> +    FORMAT_YUY2,//7
> >> +    FORMAT_UYVY,//8
> >> +    FORMAT_INDEX8,//9
> >> +    FORMAT_MONOCHROME,//10
> >> +    FORMAT_YV12 = 0xf,
> >> +    FORMAT_A8,//16
> >> +    FORMAT_NV12,//17
> >> +    FORMAT_NV16,//18
> >> +    FORMAT_RG16,//19
> >> +    FORMAT_R8,//20
> >> +    FORMAT_NV12_10BIT,//21
> >> +    FORMAT_A2R10G10B10,//22
> >> +    FORMAT_NV16_10BIT,//23
> >> +    FORMAT_INDEX1,//24
> >> +    FORMAT_INDEX2,//25
> >> +    FORMAT_INDEX4,//26
> >> +    FORMAT_P010,//27
> >> +    FORMAT_YUV444,//28
> >> +    FORMAT_YUV444_10BIT,//29
> >> +};
> >> +
> >> +enum dc_hw_yuv_color_space {
> >> +    COLOR_SPACE_601 = 0,
> >> +    COLOR_SPACE_709 = 1,
> >> +    COLOR_SPACE_2020 = 3,
> >> +};
> >> +
> >> +enum dc_hw_rotation {
> >> +    ROT_0 = 0,
> >> +    ROT_90 = 4,
> >> +    ROT_180 = 5,
> >> +    ROT_270 = 6,
> >> +    FLIP_X = 1,
> >> +    FLIP_Y = 2,
> >> +    FLIP_XY = 3,
> >> +};
> >> +
> >> +enum dc_hw_swizzle {
> >> +    SWIZZLE_ARGB = 0,
> >> +    SWIZZLE_RGBA,
> >> +    SWIZZLE_ABGR,
> >> +    SWIZZLE_BGRA,
> >> +};
> >> +
> >> +enum dc_hw_out {
> >> +    OUT_DPI,
> >> +    OUT_DP,
> >> +};
> >> +
> >> +enum dc_hw_cursor_size {
> >> +    CURSOR_SIZE_32X32 = 0,
> >> +    CURSOR_SIZE_64X64,
> >> +};
> >> +
> >> +enum dc_hw_blend_mode {
> >> +    /* out.rgb = plane_alpha * fg.rgb +
> >> +     *              (1 - (plane_alpha * fg.alpha)) * bg.rgb
> >> +     */
> >> +    BLEND_PREMULTI,
> >> +    /* out.rgb = plane_alpha * fg.alpha * fg.rgb +
> >> +     *              (1 - (plane_alpha * fg.alpha)) * bg.rgb
> >> +     */
> >> +    BLEND_COVERAGE,
> >> +    /* out.rgb = plane_alpha * fg.rgb +
> >> +     *              (1 - plane_alpha) * bg.rgb
> >> +     */
> >> +    BLEND_PIXEL_NONE,
> >
> > Can you use defines from <drm/drm_blend.h>?
> >
> >> +};
> >> +
> >> +struct dc_hw_plane_reg {
> >> +    u32 y_address;
> >> +    u32 u_address;
> >> +    u32 v_address;
> >> +    u32 y_stride;
> >> +    u32 u_stride;
> >> +    u32 v_stride;
> >> +    u32 size;
> >> +    u32 top_left;
> >> +    u32 bottom_right;
> >> +    u32 scale_factor_x;
> >> +    u32 scale_factor_y;
> >> +    u32 h_filter_coef_index;
> >> +    u32 h_filter_coef_data;
> >> +    u32 v_filter_coef_index;
> >> +    u32 v_filter_coef_data;
> >> +    u32 init_offset;
> >> +    u32 color_key;
> >> +    u32 color_key_high;
> >> +    u32 clear_value;
> >> +    u32 color_table_index;
> >> +    u32 color_table_data;
> >> +    u32 scale_config;
> >> +    u32 water_mark;
> >> +    u32 degamma_index;
> >> +    u32 degamma_data;
> >> +    u32 degamma_ex_data;
> >> +    u32 src_global_color;
> >> +    u32 dst_global_color;
> >> +    u32 blend_config;
> >> +    u32 roi_origin;
> >> +    u32 roi_size;
> >> +    u32 yuv_to_rgb_coef0;
> >> +    u32 yuv_to_rgb_coef1;
> >> +    u32 yuv_to_rgb_coef2;
> >> +    u32 yuv_to_rgb_coef3;
> >> +    u32 yuv_to_rgb_coef4;
> >> +    u32 yuv_to_rgb_coefd0;
> >> +    u32 yuv_to_rgb_coefd1;
> >> +    u32 yuv_to_rgb_coefd2;
> >> +    u32 y_clamp_bound;
> >> +    u32 uv_clamp_bound;
> >> +    u32 rgb_to_rgb_coef0;
> >> +    u32 rgb_to_rgb_coef1;
> >> +    u32 rgb_to_rgb_coef2;
> >> +    u32 rgb_to_rgb_coef3;
> >> +    u32 rgb_to_rgb_coef4;
> >> +};
> >> +
> >> +struct dc_hw_fb {
> >> +    u32 y_address;
> >> +    u32 u_address;
> >> +    u32 v_address;
> >> +    u32 clear_value;
> >> +    u32 water_mark;
> >> +    u16 y_stride;
> >> +    u16 u_stride;
> >> +    u16 v_stride;
> >> +    u16 width;
> >> +    u16 height;
> >> +    u8      format;
> >> +    u8      tile_mode;
> >> +    u8      rotation;
> >> +    u8      yuv_color_space;
> >> +    u8      swizzle;
> >> +    u8      uv_swizzle;
> >> +    u8      zpos;
> >> +    u8      display_id;
> >> +    bool    clear_enable;
> >> +    bool    dec_enable;
> >> +    bool    enable;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_scale {
> >> +    u32 scale_factor_x;
> >> +    u32 scale_factor_y;
> >> +    bool    enable;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_position {
> >> +    u16 start_x;
> >> +    u16 start_y;
> >> +    u16 end_x;
> >> +    u16 end_y;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_blend {
> >> +    u8      alpha;
> >> +    u8      blend_mode;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_colorkey {
> >> +    u32 colorkey;
> >> +    u32 colorkey_high;
> >> +    u8      transparency;
> >> +    bool dirty;
> >> +};
> >> +
> >> +struct dc_hw_roi {
> >> +    u16 x;
> >> +    u16 y;
> >> +    u16 width;
> >> +    u16 height;
> >> +    bool enable;
> >> +    bool dirty;
> >> +};
> >> +
> >> +struct dc_hw_cursor {
> >> +    u32 address;
> >> +    u16 x;
> >> +    u16 y;
> >> +    u16 hot_x;
> >> +    u16 hot_y;
> >> +    u8      size;
> >> +    u8      display_id;
> >> +    bool    enable;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_display {
> >> +    u32 bus_format;
> >> +    u16 h_active;
> >> +    u16 h_total;
> >> +    u16 h_sync_start;
> >> +    u16 h_sync_end;
> >> +    u16 v_active;
> >> +    u16 v_total;
> >> +    u16 v_sync_start;
> >> +    u16 v_sync_end;
> >> +    u8      id;
> >> +    bool    h_sync_polarity;
> >> +    bool    v_sync_polarity;
> >> +    bool    enable;
> >> +};
> >> +
> >> +struct dc_hw_gamma {
> >> +    u16 gamma[GAMMA_EX_SIZE][3];
> >> +    bool    enable;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_degamma {
> >> +    u16 degamma[DEGAMMA_SIZE][3];
> >> +    u32 mode;
> >> +    bool    dirty;
> >> +};
> >> +
> >> +struct dc_hw_plane {
> >> +    struct dc_hw_fb                 fb;
> >> +    struct dc_hw_position   pos;
> >> +    struct dc_hw_scale              scale;
> >> +    struct dc_hw_blend              blend;
> >> +    struct dc_hw_roi                roi;
> >> +    struct dc_hw_colorkey   colorkey;
> >> +    struct dc_hw_degamma    degamma;
> >> +};
> >> +
> >> +struct dc_hw_qos {
> >> +    u8        low_value;
> >> +    u8        high_value;
> >> +    bool  dirty;
> >> +};
> >> +
> >> +struct dc_hw_read {
> >> +    u32                     reg;
> >> +    u32                     value;
> >> +};
> >> +
> >> +struct dc_hw;
> >> +struct dc_hw_funcs {
> >> +    void (*gamma)(struct dc_hw *hw);
> >> +    void (*plane)(struct dc_hw *hw);
> >> +    void (*display)(struct dc_hw *hw, struct dc_hw_display *display);
> >> +};
> >> +
> >> +struct dc_hw {
> >> +    enum dc_chip_rev rev;
> >> +    enum dc_hw_out          out[DC_DISPLAY_NUM];
> >> +    void                    *hi_base;
> >> +    void                    *reg_base;
> >> +
> >> +    struct dc_hw_display display[DC_DISPLAY_NUM];
> >> +    struct dc_hw_gamma       gamma[DC_DISPLAY_NUM];
> >> +    struct dc_hw_plane       plane[DC_LAYER_NUM];
> >> +    struct dc_hw_cursor  cursor[DC_CURSOR_NUM];
> >> +    struct dc_hw_qos         qos;
> >> +    struct dc_hw_funcs       *func;
> >> +    struct vs_dc_info        *info;
> >> +};
> >> +
> >> +int dc_hw_init(struct dc_hw *hw);
> >> +void dc_hw_deinit(struct dc_hw *hw);
> >> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
> >> +                    struct dc_hw_fb *fb, struct dc_hw_scale *scale,
> >> +                    struct dc_hw_position *pos, struct dc_hw_blend *blend);
> >> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode);
> >> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi);
> >> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
> >> +                       struct dc_hw_colorkey *colorkey);
> >> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos);
> >> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor);
> >> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
> >> +                    u16 r, u16 g, u16 b);
> >> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
> >> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display);
> >> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable);
> >> +u32 dc_hw_get_interrupt(struct dc_hw *hw);
> >> +bool dc_hw_check_underflow(struct dc_hw *hw);
> >> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable);
> >> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
> >> +void dc_hw_commit(struct dc_hw *hw);
> >> +
> >> +#endif /* __VS_DC_HW_H__ */
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
> >> index da7698c3d..3cd533cfa 100644
> >> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
> >> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
> >> @@ -21,6 +21,7 @@
> >>
> >>   #include "vs_drv.h"
> >>   #include "vs_modeset.h"
> >> +#include "vs_dc.h"
> >>
> >>   #define DRV_NAME   "verisilicon"
> >>   #define DRV_DESC   "Verisilicon DRM driver"
> >> @@ -123,6 +124,7 @@ static const struct component_master_ops vs_drm_ops = {
> >>   };
> >>
> >>   static struct platform_driver *drm_sub_drivers[] = {
> >> +    &dc_platform_driver,
> >>
> >>   };
> >>
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
> >> new file mode 100644
> >> index 000000000..9bd066015
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_plane.c
> >> @@ -0,0 +1,526 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#include <drm/drm_atomic.h>
> >> +#include <drm/drm_atomic_helper.h>
> >> +#include <drm/drm_blend.h>
> >> +#include <drm/drm_gem_dma_helper.h>
> >> +#include <drm/drm_fb_dma_helper.h>
> >> +#include <drm/drm_framebuffer.h>
> >> +#include <drm/drm_plane.h>
> >> +#include <drm/drm_plane_helper.h>
> >> +
> >> +#include <drm/vs_drm.h>
> >> +
> >> +#include "vs_plane.h"
> >> +#include "vs_drv.h"
> >> +#include "vs_dc.h"
> >> +
> >> +static void vs_plane_reset(struct drm_plane *plane)
> >> +{
> >> +    struct vs_plane_state *state;
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +
> >> +    if (plane->state) {
> >> +            __drm_atomic_helper_plane_destroy_state(plane->state);
> >> +
> >> +            state = to_vs_plane_state(plane->state);
> >> +            kfree(state);
> >> +            plane->state = NULL;
> >> +    }
> >> +
> >
> > Use vs_plane_destroy_state directly. This way you won't miss a refcount
> > on blobs.
> >
> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
> >> +    if (!state)
> >> +            return;
> >> +
> >> +    state->degamma = VS_DEGAMMA_DISABLE;
> >> +    state->degamma_changed = false;
> >> +    state->base.zpos = vs_plane->id;
> >> +    memset(&state->status, 0, sizeof(state->status));
> >> +
> >> +    __drm_atomic_helper_plane_reset(plane, &state->base);
> >> +}
> >> +
> >> +static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
> >> +                                 struct vs_plane_state *ori_state)
> >> +{
> >> +    state->watermark = ori_state->watermark;
> >> +    state->color_mgmt = ori_state->color_mgmt;
> >> +    state->roi = ori_state->roi;
> >> +
> >> +    if (state->watermark)
> >> +            drm_property_blob_get(state->watermark);
> >> +    if (state->color_mgmt)
> >> +            drm_property_blob_get(state->color_mgmt);
> >> +    if (state->roi)
> >> +            drm_property_blob_get(state->roi);
> >> +}
> >> +
> >> +static int
> >> +_vs_plane_set_property_blob_from_id(struct drm_device *dev,
> >> +                                struct drm_property_blob **blob,
> >> +                                u64 blob_id,
> >> +                                size_t expected_size)
> >> +{
> >> +    struct drm_property_blob *new_blob = NULL;
> >> +
> >> +    if (blob_id) {
> >> +            new_blob = drm_property_lookup_blob(dev, blob_id);
> >> +            if (!new_blob)
> >> +                    return -EINVAL;
> >> +
> >> +            if (new_blob->length != expected_size) {
> >> +                    drm_property_blob_put(new_blob);
> >> +                    return -EINVAL;
> >> +            }
> >> +    }
> >> +
> >> +    drm_property_replace_blob(blob, new_blob);
> >> +    drm_property_blob_put(new_blob);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static struct drm_plane_state *
> >> +vs_plane_atomic_duplicate_state(struct drm_plane *plane)
> >> +{
> >> +    struct vs_plane_state *ori_state;
> >> +    struct vs_plane_state *state;
> >> +
> >> +    if (WARN_ON(!plane->state))
> >> +            return NULL;
> >> +
> >> +    ori_state = to_vs_plane_state(plane->state);
> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
> >> +    if (!state)
> >> +            return NULL;
> >> +
> >> +    __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
> >> +
> >> +    state->degamma = ori_state->degamma;
> >> +    state->degamma_changed = ori_state->degamma_changed;
> >> +
> >> +    _vs_plane_duplicate_blob(state, ori_state);
> >> +    memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
> >> +
> >> +    return &state->base;
> >> +}
> >> +
> >> +static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
> >> +                                      struct drm_plane_state *state)
> >> +{
> >> +    struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
> >> +
> >> +    __drm_atomic_helper_plane_destroy_state(state);
> >> +
> >> +    drm_property_blob_put(vs_plane_state->watermark);
> >> +    drm_property_blob_put(vs_plane_state->color_mgmt);
> >> +    drm_property_blob_put(vs_plane_state->roi);
> >> +    kfree(vs_plane_state);
> >> +}
> >> +
> >> +static int vs_plane_atomic_set_property(struct drm_plane *plane,
> >> +                                    struct drm_plane_state *state,
> >> +                                    struct drm_property *property,
> >> +                                    uint64_t val)
> >> +{
> >> +    struct drm_device *dev = plane->dev;
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +    struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
> >> +    int ret = 0;
> >> +
> >> +    if (property == vs_plane->degamma_mode) {
> >> +            if (vs_plane_state->degamma != val) {
> >> +                    vs_plane_state->degamma = val;
> >> +                    vs_plane_state->degamma_changed = true;
> >> +            } else {
> >> +                    vs_plane_state->degamma_changed = false;
> >> +            }
> >> +    } else if (property == vs_plane->watermark_prop) {
> >> +            ret = _vs_plane_set_property_blob_from_id(dev,
> >> +                                                      &vs_plane_state->watermark,
> >> +                                                      val,
> >> +                                                      sizeof(struct drm_vs_watermark));
> >> +            return ret;
> >> +    } else if (property == vs_plane->color_mgmt_prop) {
> >> +            ret = _vs_plane_set_property_blob_from_id(dev,
> >> +                                                      &vs_plane_state->color_mgmt,
> >> +                                                      val,
> >> +                                                      sizeof(struct drm_vs_color_mgmt));
> >> +            return ret;
> >> +    } else if (property == vs_plane->roi_prop) {
> >> +            ret = _vs_plane_set_property_blob_from_id(dev,
> >> +                                                      &vs_plane_state->roi,
> >> +                                                      val,
> >> +                                                      sizeof(struct drm_vs_roi));
> >> +            return ret;
> >> +    } else {
> >> +            return -EINVAL;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int vs_plane_atomic_get_property(struct drm_plane *plane,
> >> +                                    const struct drm_plane_state *state,
> >> +                                    struct drm_property *property,
> >> +                                    uint64_t *val)
> >> +{
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +    const struct vs_plane_state *vs_plane_state =
> >> +            container_of(state, const struct vs_plane_state, base);
> >> +
> >> +    if (property == vs_plane->degamma_mode)
> >> +            *val = vs_plane_state->degamma;
> >> +    else if (property == vs_plane->watermark_prop)
> >> +            *val = (vs_plane_state->watermark) ?
> >> +                                    vs_plane_state->watermark->base.id : 0;
> >> +    else if (property == vs_plane->color_mgmt_prop)
> >> +            *val = (vs_plane_state->color_mgmt) ?
> >> +                                    vs_plane_state->color_mgmt->base.id : 0;
> >
> > degamma and color management should use standard properties.
> >
> >> +    else if (property == vs_plane->roi_prop)
> >> +            *val = (vs_plane_state->roi) ?
> >> +                                    vs_plane_state->roi->base.id : 0;
> >> +    else
> >> +            return -EINVAL;
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static bool vs_format_mod_supported(struct drm_plane *plane,
> >> +                                u32 format,
> >> +                                u64 modifier)
> >> +{
> >> +    int i;
> >> +
> >> +    /* We always have to allow these modifiers:
> >> +     * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
> >> +     * 2. Not passing any modifiers is the same as explicitly passing INVALID.
> >> +     */
> >> +    if (modifier == DRM_FORMAT_MOD_LINEAR)
> >> +            return true;
> >> +
> >> +    /* Check that the modifier is on the list of the plane's supported modifiers. */
> >> +    for (i = 0; i < plane->modifier_count; i++) {
> >> +            if (modifier == plane->modifiers[i])
> >> +                    break;
> >> +    }
> >> +
> >> +    if (i == plane->modifier_count)
> >> +            return false;
> >> +
> >> +    return true;
> >> +}
> >> +
> >> +const struct drm_plane_funcs vs_plane_funcs = {
> >> +    .update_plane           = drm_atomic_helper_update_plane,
> >> +    .disable_plane          = drm_atomic_helper_disable_plane,
> >> +    .reset                  = vs_plane_reset,
> >> +    .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
> >> +    .atomic_destroy_state   = vs_plane_atomic_destroy_state,
> >> +    .atomic_set_property    = vs_plane_atomic_set_property,
> >> +    .atomic_get_property    = vs_plane_atomic_get_property,
> >> +    .format_mod_supported   = vs_format_mod_supported,
> >> +};
> >> +
> >> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
> >> +{
> >> +    const struct drm_format_info *info;
> >> +
> >> +    if (!fb)
> >> +            return 0;
> >> +
> >> +    info = drm_format_info(fb->format->format);
> >> +    if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
> >> +            return 0;
> >> +
> >> +    return info->num_planes;
> >> +}
> >> +
> >> +static int vs_plane_atomic_check(struct drm_plane *plane,
> >> +                             struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >> +                                                                             plane);
> >> +    unsigned char i, num_planes;
> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
> >> +
> >> +    if (!crtc || !fb)
> >> +            return 0;
> >> +
> >> +    num_planes = vs_get_plane_number(fb);
> >> +
> >> +    for (i = 0; i < num_planes; i++) {
> >> +            dma_addr_t dma_addr;
> >> +
> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
> >> +            plane_state->dma_addr[i] = dma_addr;
> >> +    }
> >> +
> >> +    return vs_dc_check_plane(dc, plane, state);
> >> +}
> >> +
> >> +static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
> >> +                                    struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >> +                                                                      plane);
> >> +    unsigned char i, num_planes;
> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
> >> +
> >> +    if (!crtc || !fb)
> >> +            return 0;
> >> +
> >> +    num_planes = vs_get_plane_number(fb);
> >> +
> >> +    for (i = 0; i < num_planes; i++) {
> >> +            dma_addr_t dma_addr;
> >> +
> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
> >> +            plane_state->dma_addr[i] = dma_addr;
> >> +    }
> >> +
> >> +    return vs_dc_check_cursor_plane(dc, plane, state);
> >> +}
> >> +
> >> +static void vs_plane_atomic_update(struct drm_plane *plane,
> >> +                               struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> >> +                                                                      plane);
> >
> > New line after the equal sign will be better.
> >
> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> >> +                                                                      plane);
> >> +
> >> +    unsigned char i, num_planes;
> >> +    struct drm_framebuffer *fb;
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    if (!new_state->fb || !new_state->crtc)
> >> +            return;
> >
> > if (!new_state->visible) ?
> >
> >> +
> >> +    fb = new_state->fb;
> >> +
> >> +    drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
> >> +
> >> +    num_planes = vs_get_plane_number(fb);
> >> +
> >> +    for (i = 0; i < num_planes; i++) {
> >> +            dma_addr_t dma_addr;
> >> +
> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
> >> +            plane_state->dma_addr[i] = dma_addr;
> >> +    }
> >> +
> >> +    plane_state->status.src = drm_plane_state_src(new_state);
> >> +    plane_state->status.dest = drm_plane_state_dest(new_state);
> >> +
> >> +    vs_dc_update_plane(dc, vs_plane, plane, state);
> >> +}
> >> +
> >> +static void vs_cursor_plane_atomic_update(struct drm_plane *plane,
> >> +                                      struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> >> +                                                                       plane);
> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> >> +                                                                       plane);
> >> +    unsigned char i, num_planes;
> >> +    struct drm_framebuffer *fb;
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    if (!new_state->fb || !new_state->crtc)
> >
> > and here.
> >
> >> +            return;
> >> +
> >> +    fb = new_state->fb;
> >> +    drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
> >> +
> >> +    num_planes = vs_get_plane_number(fb);
> >> +
> >> +    for (i = 0; i < num_planes; i++) {
> >> +            dma_addr_t dma_addr;
> >> +
> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
> >> +            plane_state->dma_addr[i] = dma_addr;
> >> +    }
> >> +
> >> +    plane_state->status.src = drm_plane_state_src(new_state);
> >> +    plane_state->status.dest = drm_plane_state_dest(new_state);
> >> +
> >> +    vs_dc_update_cursor_plane(dc, vs_plane, plane, state);
> >> +}
> >> +
> >> +static void vs_plane_atomic_disable(struct drm_plane *plane,
> >> +                                struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> >> +                                                                       plane);
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    vs_dc_disable_plane(dc, vs_plane, old_state);
> >> +}
> >> +
> >> +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane,
> >> +                                       struct drm_atomic_state *state)
> >> +{
> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> >> +                                                                       plane);
> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> +
> >> +    vs_dc_disable_cursor_plane(dc, vs_plane, old_state);
> >> +}
> >> +
> >> +const struct drm_plane_helper_funcs primary_plane_helpers = {
> >> +    .atomic_check   = vs_plane_atomic_check,
> >> +    .atomic_update  = vs_plane_atomic_update,
> >> +    .atomic_disable = vs_plane_atomic_disable,
> >> +};
> >> +
> >> +const struct drm_plane_helper_funcs overlay_plane_helpers = {
> >> +    .atomic_check   = vs_plane_atomic_check,
> >> +    .atomic_update  = vs_plane_atomic_update,
> >> +    .atomic_disable = vs_plane_atomic_disable,
> >> +};
> >> +
> >> +const struct drm_plane_helper_funcs cursor_plane_helpers = {
> >> +    .atomic_check   = vs_cursor_plane_atomic_check,
> >> +    .atomic_update  = vs_cursor_plane_atomic_update,
> >> +    .atomic_disable = vs_cursor_plane_atomic_disable,
> >> +};
> >> +
> >> +static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
> >> +    { VS_DEGAMMA_DISABLE,   "disabled" },
> >> +    { VS_DEGAMMA_BT709,     "preset degamma for BT709" },
> >> +    { VS_DEGAMMA_BT2020,    "preset degamma for BT2020" },
> >> +};
> >> +
> >> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
> >> +                             struct vs_plane_info *info,
> >> +                             unsigned int layer_num,
> >> +                             unsigned int possible_crtcs)
> >> +{
> >> +    struct vs_plane *plane;
> >> +    int ret;
> >> +
> >> +    if (!info)
> >> +            return NULL;
> >> +
> >> +    plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
> >> +                                       possible_crtcs,
> >> +                                       &vs_plane_funcs,
> >> +                                       info->formats, info->num_formats,
> >> +                                       info->modifiers, info->type,
> >> +                                       info->name ? info->name : NULL);
> >> +    if (IS_ERR(plane))
> >> +            return ERR_CAST(plane);
> >> +
> >> +    if (info->type == DRM_PLANE_TYPE_PRIMARY)
> >> +            drm_plane_helper_add(&plane->base, &primary_plane_helpers);
> >> +    else if (info->type == DRM_PLANE_TYPE_CURSOR)
> >> +            drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
> >> +    else
> >> +            drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
> >> +
> >> +    /* Set up the plane properties */
> >> +    if (info->degamma_size) {
> >> +            plane->degamma_mode =
> >> +            drm_property_create_enum(drm_dev, 0,
> >> +                                     "DEGAMMA_MODE",
> >> +                                     vs_degamma_mode_enum_list,
> >> +                                     ARRAY_SIZE(vs_degamma_mode_enum_list));
> >> +
> >> +            if (!plane->degamma_mode)
> >> +                    return NULL;
> >> +
> >> +            drm_object_attach_property(&plane->base.base,
> >> +                                       plane->degamma_mode,
> >> +                                       VS_DEGAMMA_DISABLE);
> >> +    }
> >> +
> >> +    if (info->rotation) {
> >> +            ret = drm_plane_create_rotation_property(&plane->base,
> >> +                                                     DRM_MODE_ROTATE_0,
> >> +                                                     info->rotation);
> >> +            if (ret)
> >> +                    return NULL;
> >> +    }
> >> +
> >> +    if (info->blend_mode) {
> >> +            ret = drm_plane_create_blend_mode_property(&plane->base,
> >> +                                                       info->blend_mode);
> >> +            if (ret)
> >> +                    return NULL;
> >> +            ret = drm_plane_create_alpha_property(&plane->base);
> >> +            if (ret)
> >> +                    return NULL;
> >> +    }
> >> +
> >> +    if (info->color_encoding) {
> >> +            ret = drm_plane_create_color_properties(&plane->base,
> >> +                                                    info->color_encoding,
> >> +                                                    BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
> >> +                                                    DRM_COLOR_YCBCR_BT709,
> >> +                                                    DRM_COLOR_YCBCR_LIMITED_RANGE);
> >> +            if (ret)
> >> +                    return NULL;
> >> +    }
> >> +
> >> +    if (info->zpos != 255) {
> >> +            ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
> >> +                                                 layer_num - 1);
> >> +            if (ret)
> >> +                    return NULL;
> >> +    } else {
> >> +            ret = drm_plane_create_zpos_immutable_property(&plane->base,
> >> +                                                           info->zpos);
> >> +            if (ret)
> >> +                    return NULL;
> >> +    }
> >> +
> >> +    if (info->watermark) {
> >> +            plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
> >> +                                                        "WATERMARK", 0);
> >> +            if (!plane->watermark_prop)
> >> +                    return NULL;
> >> +            drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
> >> +    }
> >> +
> >> +    if (info->color_mgmt) {
> >> +            plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
> >> +                                                         "COLOR_CONFIG", 0);
> >> +            if (!plane->color_mgmt_prop)
> >> +                    return NULL;
> >> +
> >> +            drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
> >> +    }
> >> +
> >> +    if (info->roi) {
> >> +            plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
> >> +                                                  "ROI", 0);
> >> +            if (!plane->roi_prop)
> >> +                    return NULL;
> >> +
> >> +            drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
> >> +    }
> >> +
> >> +    return plane;
> >> +}
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
> >> new file mode 100644
> >> index 000000000..554b74e96
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_plane.h
> >> @@ -0,0 +1,58 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#ifndef __VS_PLANE_H__
> >> +#define __VS_PLANE_H__
> >> +
> >> +#include <drm/drm_fourcc.h>
> >> +#include <drm/drm_plane_helper.h>
> >> +
> >> +#include "vs_type.h"
> >> +
> >> +struct vs_plane_status {
> >> +    u32 tile_mode;
> >> +    struct drm_rect src;
> >> +    struct drm_rect dest;
> >> +};
> >> +
> >> +struct vs_plane_state {
> >> +    struct drm_plane_state base;
> >> +    struct vs_plane_status status; /* for debugfs */
> >> +
> >> +    struct drm_property_blob *watermark;
> >> +    struct drm_property_blob *color_mgmt;
> >> +    struct drm_property_blob *roi;
> >> +    dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES];
> >> +
> >> +    u32 degamma;
> >> +    bool degamma_changed;
> >> +};
> >> +
> >> +struct vs_plane {
> >> +    struct drm_plane base;
> >> +    u8 id;
> >> +
> >> +    struct drm_property *degamma_mode;
> >> +    struct drm_property *watermark_prop;
> >> +    struct drm_property *color_mgmt_prop;
> >> +    struct drm_property *roi_prop;
> >> +};
> >> +
> >> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
> >> +                             struct vs_plane_info *info,
> >> +                             unsigned int layer_num,
> >> +                             unsigned int possible_crtcs);
> >> +
> >> +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
> >> +{
> >> +    return container_of(plane, struct vs_plane, base);
> >> +}
> >> +
> >> +static inline struct vs_plane_state *
> >> +to_vs_plane_state(struct drm_plane_state *state)
> >> +{
> >> +    return container_of(state, struct vs_plane_state, base);
> >> +}
> >> +#endif /* __VS_PLANE_H__ */
> >> diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
> >> new file mode 100644
> >> index 000000000..7d3378e29
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/verisilicon/vs_type.h
> >> @@ -0,0 +1,69 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> + */
> >> +
> >> +#ifndef __VS_TYPE_H__
> >> +#define __VS_TYPE_H__
> >> +
> >> +#include <drm/drm_plane.h>
> >> +#include <drm/drm_plane_helper.h>
> >> +
> >> +struct vs_plane_info {
> >> +    const char *name;
> >> +    u8 id;
> >> +    enum drm_plane_type type;
> >> +    unsigned int num_formats;
> >> +    const u32 *formats;
> >> +    u8 num_modifiers;
> >> +    const u64 *modifiers;
> >> +    unsigned int min_width;
> >> +    unsigned int min_height;
> >> +    unsigned int max_width;
> >> +    unsigned int max_height;
> >> +    unsigned int rotation;
> >> +    unsigned int blend_mode;
> >> +    unsigned int color_encoding;
> >> +
> >> +    /* 0 means no de-gamma LUT */
> >> +    unsigned int degamma_size;
> >> +
> >> +    int min_scale; /* 16.16 fixed point */
> >> +    int max_scale; /* 16.16 fixed point */
> >> +
> >> +    /* default zorder value,
> >> +     * and 255 means unsupported zorder capability
> >> +     */
> >> +    u8       zpos;
> >> +
> >> +    bool watermark;
> >> +    bool color_mgmt;
> >> +    bool roi;
> >> +};
> >> +
> >> +struct vs_dc_info {
> >> +    const char *name;
> >> +
> >> +    u8 panel_num;
> >> +
> >> +    /* planes */
> >> +    u8 plane_num;
> >> +    const struct vs_plane_info *planes;
> >> +
> >> +    u8 layer_num;
> >> +    unsigned int max_bpc;
> >> +    unsigned int color_formats;
> >> +
> >> +    /* 0 means no gamma LUT */
> >> +    u16 gamma_size;
> >> +    u8 gamma_bits;
> >> +
> >> +    u16 pitch_alignment;
> >> +
> >> +    bool pipe_sync;
> >> +    bool background;
> >> +    bool panel_sync;
> >> +    bool cap_dec;
> >> +};
> >> +
> >> +#endif /* __VS_TYPE_H__ */
> >
Keith Zhao Nov. 15, 2023, 1:30 p.m. UTC | #3
On 2023/11/14 18:59, Dmitry Baryshkov wrote:
> On Tue, 14 Nov 2023 at 12:42, Keith Zhao <keith.zhao@starfivetech.com> wrote:
>>
>>
>>
>> On 2023/10/26 3:28, Dmitry Baryshkov wrote:
>> > On 25/10/2023 13:39, Keith Zhao wrote:
>> >> add 2 crtcs and 8 planes in vs-drm
>> >>
>> >> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
>> >> ---
>> >>   drivers/gpu/drm/verisilicon/Makefile   |    8 +-
>> >>   drivers/gpu/drm/verisilicon/vs_crtc.c  |  257 ++++
>> >>   drivers/gpu/drm/verisilicon/vs_crtc.h  |   43 +
>> >>   drivers/gpu/drm/verisilicon/vs_dc.c    | 1002 ++++++++++++
>> >>   drivers/gpu/drm/verisilicon/vs_dc.h    |   80 +
>> >>   drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1959 ++++++++++++++++++++++++
>> >>   drivers/gpu/drm/verisilicon/vs_dc_hw.h |  492 ++++++
>> >>   drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
>> >>   drivers/gpu/drm/verisilicon/vs_plane.c |  526 +++++++
>> >>   drivers/gpu/drm/verisilicon/vs_plane.h |   58 +
>> >>   drivers/gpu/drm/verisilicon/vs_type.h  |   69 +
>> >>   11 files changed, 4494 insertions(+), 2 deletions(-)
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
>> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
>> >>
>> >> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
>> >> index 7d3be305b..1d48016ca 100644
>> >> --- a/drivers/gpu/drm/verisilicon/Makefile
>> >> +++ b/drivers/gpu/drm/verisilicon/Makefile
>> >> @@ -1,7 +1,11 @@
>> >>   # SPDX-License-Identifier: GPL-2.0
>> >>
>> >> -vs_drm-objs := vs_drv.o \
>> >> -            vs_modeset.o
>> >> +vs_drm-objs := vs_dc_hw.o \
>> >> +            vs_dc.o \
>> >> +            vs_crtc.o \
>> >> +            vs_drv.o \
>> >> +            vs_modeset.o \
>> >> +            vs_plane.o
>> >>
>> >>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
>> >>
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
>> >> new file mode 100644
>> >> index 000000000..8a658ea77
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
>> >> @@ -0,0 +1,257 @@
>> >> +// SPDX-License-Identifier: GPL-2.0
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + *
>> >> + */
>> >> +
>> >> +#include <linux/clk.h>
>> >> +#include <linux/debugfs.h>
>> >> +#include <linux/media-bus-format.h>
>> >> +
>> >> +#include <drm/drm_atomic_helper.h>
>> >> +#include <drm/drm_atomic.h>
>> >> +#include <drm/drm_crtc.h>
>> >> +#include <drm/drm_gem_atomic_helper.h>
>> >> +#include <drm/drm_vblank.h>
>> >> +#include <drm/vs_drm.h>
>> >> +
>> >> +#include "vs_crtc.h"
>> >> +#include "vs_dc.h"
>> >> +#include "vs_drv.h"
>> >> +
>> >> +static void vs_crtc_reset(struct drm_crtc *crtc)
>> >> +{
>> >> +    struct vs_crtc_state *state;
>> >> +
>> >> +    if (crtc->state) {
>> >> +            __drm_atomic_helper_crtc_destroy_state(crtc->state);
>> >> +
>> >> +            state = to_vs_crtc_state(crtc->state);
>> >> +            kfree(state);
>> >> +            crtc->state = NULL;
>> >> +    }
>> >
>> > You can call your crtc_destroy_state function directly here.
>> >
>> >> +
>> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> >> +    if (!state)
>> >> +            return;
>> >> +
>> >> +    __drm_atomic_helper_crtc_reset(crtc, &state->base);
>> >> +}
>> >> +
>> >> +static struct drm_crtc_state *
>> >> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
>> >> +{
>> >> +    struct vs_crtc_state *ori_state;
>> >
>> > It might be a matter of taste, but it is usually old_state.
>> >
>> >> +    struct vs_crtc_state *state;
>> >> +
>> >> +    if (!crtc->state)
>> >> +            return NULL;
>> >> +
>> >> +    ori_state = to_vs_crtc_state(crtc->state);
>> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> >> +    if (!state)
>> >> +            return NULL;
>> >> +
>> >> +    __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
>> >> +
>> >> +    state->output_fmt = ori_state->output_fmt;
>> >> +    state->encoder_type = ori_state->encoder_type;
>> >> +    state->bpp = ori_state->bpp;
>> >> +    state->underflow = ori_state->underflow;
>> >
>> > Can you use kmemdup instead?
>> >
>> >> +
>> >> +    return &state->base;
>> >> +}
>> >> +
>> >> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
>> >> +                                     struct drm_crtc_state *state)
>> >> +{
>> >> +    __drm_atomic_helper_crtc_destroy_state(state);
>> >> +    kfree(to_vs_crtc_state(state));
>> >> +}
>> >> +
>> >> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
>> >> +{
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    vs_dc_enable_vblank(dc, true);
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
>> >> +{
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    vs_dc_enable_vblank(dc, false);
>> >> +}
>> >> +
>> >> +static const struct drm_crtc_funcs vs_crtc_funcs = {
>> >> +    .set_config             = drm_atomic_helper_set_config,
>> >> +    .page_flip              = drm_atomic_helper_page_flip,
>> >
>> > destroy is required, see drm_mode_config_cleanup()
>>
>> hi Dmitry:
>> if define destroy in drm_crtc_funcs,
>> it will make __drmm_crtc_init_with_planes unhappy
> 
> Ack, I missed that you have been using drmm_crtc_init. BTW, I checked
> your code, you should be able to switch drm
> drmm_crtc_alloc_with_planes().
> 
yes 
I done the replace and it can work well.

>>
>> see:
>> __printf(6, 0)
>> static int __drmm_crtc_init_with_planes(struct drm_device *dev,
>>                                         struct drm_crtc *crtc,
>>                                         struct drm_plane *primary,
>>                                         struct drm_plane *cursor,
>>                                         const struct drm_crtc_funcs *funcs,
>>                                         const char *name,
>>                                         va_list args)
>> {
>>         int ret;
>>
>>         drm_WARN_ON(dev, funcs && funcs->destroy);
>>
>> ........
>> }
>>
>> It should not need to be defined here, I think
>>
>> >
>> >> +    .reset                  = vs_crtc_reset,
>> >> +    .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
>> >> +    .atomic_destroy_state   = vs_crtc_atomic_destroy_state,
>> >
>> > please consider adding atomic_print_state to output driver-specific bits.
>> >
>> >> +    .enable_vblank          = vs_crtc_enable_vblank,
>> >> +    .disable_vblank         = vs_crtc_disable_vblank,
>> >> +};
>> >> +
>> >> +static u8 cal_pixel_bits(u32 bus_format)
>> >
>> > This looks like a generic helper code, which can go to a common place.
I don't know if I understand correctly
Here I remove static
Add 2 lines in vs_drv.h

/* vs_crtc.c */
u8 cal_pixel_bits(u32 bus_format);

to make it common 

>> >
>> >> +{
>> >> +    u8 bpp;
>> >> +
>> >> +    switch (bus_format) {
>> >> +    case MEDIA_BUS_FMT_RGB565_1X16:
>> >> +    case MEDIA_BUS_FMT_UYVY8_1X16:
>> >> +            bpp = 16;
>> >> +            break;
>> >> +    case MEDIA_BUS_FMT_RGB666_1X18:
>> >> +    case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
>> >> +            bpp = 18;
>> >> +            break;
>> >> +    case MEDIA_BUS_FMT_UYVY10_1X20:
>> >> +            bpp = 20;
>> >> +            break;
>> >> +    case MEDIA_BUS_FMT_BGR888_1X24:
>> >> +    case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
>> >> +    case MEDIA_BUS_FMT_YUV8_1X24:
>> >> +            bpp = 24;
>> >> +            break;
>> >> +    case MEDIA_BUS_FMT_RGB101010_1X30:
>> >> +    case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
>> >> +    case MEDIA_BUS_FMT_YUV10_1X30:
>> >> +            bpp = 30;
>> >> +            break;
>> >> +    default:
>> >> +            bpp = 24;
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    return bpp;
>> >> +}
>> >> +
>> >> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
>> >> +                              struct drm_atomic_state *state)
>> >> +{
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
>> >> +
>> >> +    vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
>> >> +
>> >> +    vs_dc_enable(dc, crtc);
>> >> +    drm_crtc_vblank_on(crtc);
>> >> +}
>> >> +
>> >> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
>> >> +                               struct drm_atomic_state *state)
>> >> +{
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    drm_crtc_vblank_off(crtc);
>> >> +
>> >> +    vs_dc_disable(dc, crtc);
>> >> +
>> >> +    if (crtc->state->event && !crtc->state->active) {
>> >> +            spin_lock_irq(&crtc->dev->event_lock);
>> >> +            drm_crtc_send_vblank_event(crtc, crtc->state->event);
>> >> +            spin_unlock_irq(&crtc->dev->event_lock);
>> >> +
>> >> +            crtc->state->event = NULL;
>> >
>> > I think even should be cleared within the lock.
>> >
>> >> +    }
>> >> +}
>> >> +
>> >> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
>> >> +                             struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
>> >> +                                                                      crtc);
>> >> +
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct device *dev = vs_crtc->dev;
>> >> +    struct drm_property_blob *blob = crtc->state->gamma_lut;
>> >> +    struct drm_color_lut *lut;
>> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
>> >> +
>> >> +    if (crtc_state->color_mgmt_changed) {
>> >> +            if (blob && blob->length) {
>> >> +                    lut = blob->data;
>> >> +                    vs_dc_set_gamma(dc, crtc, lut,
>> >> +                                    blob->length / sizeof(*lut));
>> >> +                    vs_dc_enable_gamma(dc, crtc, true);
>> >> +            } else {
>> >> +                    vs_dc_enable_gamma(dc, crtc, false);
>> >> +            }
>> >> +    }
>> >> +}
>> >> +
>> >> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
>> >> +                             struct drm_atomic_state *state)
>> >> +{
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct drm_pending_vblank_event *event = crtc->state->event;
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    vs_dc_commit(dc);
>> >> +
>> >> +    if (event) {
>> >> +            WARN_ON(drm_crtc_vblank_get(crtc) != 0);
>> >> +
>> >> +            spin_lock_irq(&crtc->dev->event_lock);
>> >> +            drm_crtc_arm_vblank_event(crtc, event);
>> >> +            spin_unlock_irq(&crtc->dev->event_lock);
>> >> +            crtc->state->event = NULL;
>> >
>> > I think even should be cleared within the lock.
>> >
>> >> +    }
>> >> +}
>> >> +
>> >> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
>> >> +    .atomic_check = drm_crtc_helper_atomic_check,
>> >> +    .atomic_enable  = vs_crtc_atomic_enable,
>> >> +    .atomic_disable = vs_crtc_atomic_disable,
>> >> +    .atomic_begin   = vs_crtc_atomic_begin,
>> >> +    .atomic_flush   = vs_crtc_atomic_flush,
>> >> +};
>> >> +
>> >> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
>> >> +    { VS_SINGLE_DC,                         "single dc mode" },
>> >> +    { VS_MULTI_DC_PRIMARY,          "primary dc for multi dc mode" },
>> >> +    { VS_MULTI_DC_SECONDARY,        "secondary dc for multi dc mode" },
>> >> +};
>> >> +
>> >> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
>> >> +                           struct vs_dc_info *info)
>> >> +{
>> >> +    struct vs_crtc *crtc;
>> >> +    int ret;
>> >> +
>> >> +    if (!info)
>> >> +            return NULL;
>> >> +
>> >> +    crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL);
>> >> +    if (!crtc)
>> >> +            return NULL;
>> >> +
>> >> +    ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base,
>> >> +                                     NULL, NULL, &vs_crtc_funcs,
>> >> +                                     info->name ? info->name : NULL);
>> >
>> > It might be better to add drmm_crtc_init() helper.
	drmm_crtc_alloc_with_planes used:
	...
	struct vs_crtc *crtc;
	int ret;

	if (!info)
		return NULL;

	crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base,
					       NULL, NULL,
					       &vs_crtc_funcs, info->name ? info->name : NULL);
	...

>> >
>> >> +    if (ret)
>> >> +            return NULL;
>> >> +
>> >> +    drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
>> >> +
>> >> +    if (info->gamma_size) {
>> >> +            ret = drm_mode_crtc_set_gamma_size(&crtc->base,
>> >> +                                               info->gamma_size);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +
>> >> +            drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
>> >> +                                       info->gamma_size);
>> >> +    }
>> >> +
>> >> +    crtc->max_bpc = info->max_bpc;
>> >> +    crtc->color_formats = info->color_formats;
>> >> +    return crtc;
>> >> +}
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
>> >> new file mode 100644
>> >> index 000000000..526dd63e5
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
>> >> @@ -0,0 +1,43 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#ifndef __VS_CRTC_H__
>> >> +#define __VS_CRTC_H__
>> >> +
>> >> +#include <drm/drm_crtc.h>
>> >> +#include <drm/drm_crtc_helper.h>
>> >> +
>> >> +#include "vs_type.h"
>> >> +
>> >> +struct vs_crtc_state {
>> >> +    struct drm_crtc_state base;
>> >> +
>> >> +    u32 output_fmt;
>> >> +    u8 encoder_type;
>> >> +    u8 bpp;
>> >> +    bool underflow;
>> >> +};
>> >> +
>> >> +struct vs_crtc {
>> >> +    struct drm_crtc base;
>> >> +    struct device *dev;
>> >> +    unsigned int max_bpc;
>> >> +    unsigned int color_formats;
>> >> +};
>> >> +
>> >> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
>> >> +                           struct vs_dc_info *info);
>> >> +
>> >> +static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
>> >> +{
>> >> +    return container_of(crtc, struct vs_crtc, base);
>> >> +}
>> >> +
>> >> +static inline struct vs_crtc_state *
>> >> +to_vs_crtc_state(struct drm_crtc_state *state)
>> >> +{
>> >> +    return container_of(state, struct vs_crtc_state, base);
>> >> +}
>> >> +#endif /* __VS_CRTC_H__ */
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
>> >> new file mode 100644
>> >> index 000000000..b5ab92d98
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc.c
>> >> @@ -0,0 +1,1002 @@
>> >> +// SPDX-License-Identifier: GPL-2.0
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#include <linux/component.h>
>> >> +#include <linux/clk.h>
>> >> +#include <linux/of.h>
>> >> +#include <linux/of_device.h>
>> >> +#include <linux/pm_runtime.h>
>> >> +#include <linux/reset.h>
>> >> +
>> >> +#include <drm/drm_atomic.h>
>> >> +#include <drm/drm_atomic_helper.h>
>> >> +#include <drm/drm_blend.h>
>> >> +#include <drm/drm_framebuffer.h>
>> >> +#include <drm/drm_vblank.h>
>> >> +#include <drm/vs_drm.h>
>> >> +
>> >> +#include "vs_dc_hw.h"
>> >> +#include "vs_dc.h"
>> >> +#include "vs_drv.h"
>> >> +
>> >> +static const char * const vout_clocks[] = {
>> >> +    "noc_bus",
>> >> +    "channel0",
>> >> +    "channel1",
>> >> +    "dc_core",
>> >> +    "axi_core",
>> >> +    "ahb",
>> >> +    "hdmi_tx",
>> >> +    "dc_parent",
>> >> +
>> >> +};
>> >> +
>> >> +static const char * const vout_resets[] = {
>> >> +    "axi",
>> >> +    "ahb",
>> >> +    "core",
>> >> +};
>> >> +
>> >> +static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
>> >> +{
>> >> +    u8 f = FORMAT_A8R8G8B8;
>> >> +
>> >> +    switch (format) {
>> >> +    case DRM_FORMAT_XRGB4444:
>> >> +    case DRM_FORMAT_RGBX4444:
>> >> +    case DRM_FORMAT_XBGR4444:
>> >> +    case DRM_FORMAT_BGRX4444:
>> >> +            f = FORMAT_X4R4G4B4;
>> >> +            break;
>> >> +    case DRM_FORMAT_ARGB4444:
>> >> +    case DRM_FORMAT_RGBA4444:
>> >> +    case DRM_FORMAT_ABGR4444:
>> >> +    case DRM_FORMAT_BGRA4444:
>> >> +            f = FORMAT_A4R4G4B4;
>> >> +            break;
>> >> +    case DRM_FORMAT_XRGB1555:
>> >> +    case DRM_FORMAT_RGBX5551:
>> >> +    case DRM_FORMAT_XBGR1555:
>> >> +    case DRM_FORMAT_BGRX5551:
>> >> +            f = FORMAT_X1R5G5B5;
>> >> +            break;
>> >> +    case DRM_FORMAT_ARGB1555:
>> >> +    case DRM_FORMAT_RGBA5551:
>> >> +    case DRM_FORMAT_ABGR1555:
>> >> +    case DRM_FORMAT_BGRA5551:
>> >> +            f = FORMAT_A1R5G5B5;
>> >> +            break;
>> >> +    case DRM_FORMAT_RGB565:
>> >> +    case DRM_FORMAT_BGR565:
>> >> +            f = FORMAT_R5G6B5;
>> >> +            break;
>> >> +    case DRM_FORMAT_XRGB8888:
>> >> +    case DRM_FORMAT_RGBX8888:
>> >> +    case DRM_FORMAT_XBGR8888:
>> >> +    case DRM_FORMAT_BGRX8888:
>> >> +            f = FORMAT_X8R8G8B8;
>> >> +            break;
>> >> +    case DRM_FORMAT_ARGB8888:
>> >> +    case DRM_FORMAT_RGBA8888:
>> >> +    case DRM_FORMAT_ABGR8888:
>> >> +    case DRM_FORMAT_BGRA8888:
>> >> +            f = FORMAT_A8R8G8B8;
>> >> +            break;
>> >> +    case DRM_FORMAT_YUYV:
>> >> +    case DRM_FORMAT_YVYU:
>> >> +            f = FORMAT_YUY2;
>> >> +            break;
>> >> +    case DRM_FORMAT_UYVY:
>> >> +    case DRM_FORMAT_VYUY:
>> >> +            f = FORMAT_UYVY;
>> >> +            break;
>> >> +    case DRM_FORMAT_YUV420:
>> >> +    case DRM_FORMAT_YVU420:
>> >> +            f = FORMAT_YV12;
>> >> +            break;
>> >> +    case DRM_FORMAT_NV21:
>> >> +            f = FORMAT_NV12;
>> >> +            break;
>> >> +    case DRM_FORMAT_NV16:
>> >> +    case DRM_FORMAT_NV61:
>> >> +            f = FORMAT_NV16;
>> >> +            break;
>> >> +    case DRM_FORMAT_P010:
>> >> +            f = FORMAT_P010;
>> >> +            break;
>> >> +    case DRM_FORMAT_ARGB2101010:
>> >> +    case DRM_FORMAT_RGBA1010102:
>> >> +    case DRM_FORMAT_ABGR2101010:
>> >> +    case DRM_FORMAT_BGRA1010102:
>> >> +            f = FORMAT_A2R10G10B10;
>> >> +            break;
>> >> +    case DRM_FORMAT_NV12:
>> >> +            f = FORMAT_NV12;
>> >> +            break;
>> >> +    case DRM_FORMAT_YUV444:
>> >> +            f = FORMAT_YUV444;
>> >> +            break;
>> >> +    default:
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    fb->format = f;
>> >> +}
>> >> +
>> >> +static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
>> >> +{
>> >> +    fb->swizzle = SWIZZLE_ARGB;
>> >> +    fb->uv_swizzle = 0;
>> >> +
>> >> +    switch (format) {
>> >> +    case DRM_FORMAT_RGBX4444:
>> >> +    case DRM_FORMAT_RGBA4444:
>> >> +    case DRM_FORMAT_RGBX5551:
>> >> +    case DRM_FORMAT_RGBA5551:
>> >> +    case DRM_FORMAT_RGBX8888:
>> >> +    case DRM_FORMAT_RGBA8888:
>> >> +    case DRM_FORMAT_RGBA1010102:
>> >> +            fb->swizzle = SWIZZLE_RGBA;
>> >> +            break;
>> >> +    case DRM_FORMAT_XBGR4444:
>> >> +    case DRM_FORMAT_ABGR4444:
>> >> +    case DRM_FORMAT_XBGR1555:
>> >> +    case DRM_FORMAT_ABGR1555:
>> >> +    case DRM_FORMAT_BGR565:
>> >> +    case DRM_FORMAT_XBGR8888:
>> >> +    case DRM_FORMAT_ABGR8888:
>> >> +    case DRM_FORMAT_ABGR2101010:
>> >> +            fb->swizzle = SWIZZLE_ABGR;
>> >> +            break;
>> >> +    case DRM_FORMAT_BGRX4444:
>> >> +    case DRM_FORMAT_BGRA4444:
>> >> +    case DRM_FORMAT_BGRX5551:
>> >> +    case DRM_FORMAT_BGRA5551:
>> >> +    case DRM_FORMAT_BGRX8888:
>> >> +    case DRM_FORMAT_BGRA8888:
>> >> +    case DRM_FORMAT_BGRA1010102:
>> >> +            fb->swizzle = SWIZZLE_BGRA;
>> >> +            break;
>> >> +    case DRM_FORMAT_YVYU:
>> >> +    case DRM_FORMAT_VYUY:
>> >> +    case DRM_FORMAT_NV21:
>> >> +    case DRM_FORMAT_NV61:
>> >> +            fb->uv_swizzle = 1;
>> >> +            break;
>> >> +    default:
>> >> +            break;
>> >> +    }
>> >> +}
>> >> +
>> >> +static inline void update_watermark(struct drm_property_blob *watermark,
>> >> +                                struct dc_hw_fb *fb)
>> >> +{
>> >> +    struct drm_vs_watermark *data;
>> >> +
>> >> +    fb->water_mark = 0;
>> >> +
>> >> +    if (watermark) {
>> >> +            data = watermark->data;
>> >> +            fb->water_mark = data->watermark & 0xFFFFF;
>> >> +    }
>> >> +}
>> >> +
>> >> +static inline u8 to_vs_rotation(unsigned int rotation)
>> >> +{
>> >> +    u8 rot;
>> >> +
>> >> +    switch (rotation & DRM_MODE_REFLECT_MASK) {
>> >> +    case DRM_MODE_REFLECT_X:
>> >> +            rot = FLIP_X;
>> >> +            return rot;
>> >> +    case DRM_MODE_REFLECT_Y:
>> >> +            rot = FLIP_Y;
>> >> +            return rot;
>> >> +    case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
>> >> +            rot = FLIP_XY;
>> >> +            return rot;
>> >> +    default:
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    switch (rotation & DRM_MODE_ROTATE_MASK) {
>> >> +    case DRM_MODE_ROTATE_0:
>> >> +            rot = ROT_0;
>> >> +            break;
>> >> +    case DRM_MODE_ROTATE_90:
>> >> +            rot = ROT_90;
>> >> +            break;
>> >> +    case DRM_MODE_ROTATE_180:
>> >> +            rot = ROT_180;
>> >> +            break;
>> >> +    case DRM_MODE_ROTATE_270:
>> >> +            rot = ROT_270;
>> >> +            break;
>> >> +    default:
>> >> +            rot = ROT_0;
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    return rot;
>> >> +}
>> >> +
>> >> +static inline u8 to_vs_yuv_color_space(u32 color_space)
>> >> +{
>> >> +    u8 cs;
>> >> +
>> >> +    switch (color_space) {
>> >> +    case DRM_COLOR_YCBCR_BT601:
>> >> +            cs = COLOR_SPACE_601;
>> >> +            break;
>> >> +    case DRM_COLOR_YCBCR_BT709:
>> >> +            cs = COLOR_SPACE_709;
>> >> +            break;
>> >> +    case DRM_COLOR_YCBCR_BT2020:
>> >> +            cs = COLOR_SPACE_2020;
>> >> +            break;
>> >> +    default:
>> >> +            cs = COLOR_SPACE_601;
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    return cs;
>> >> +}
>> >> +
>> >> +static inline u8 to_vs_tile_mode(u64 modifier)
>> >> +{
>> >> +    if (modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
>> >> +            return DC_TILE_MODE4X4;
>> >> +
>> >> +    return (u8)(modifier & DRM_FORMAT_MOD_VERISILICON_NORM_MODE_MASK);
>> >> +}
>> >> +
>> >> +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
>> >> +{
>> >> +    u8 panel_num = dc->hw.info->panel_num;
>> >> +    u32 index = drm_crtc_index(crtc);
>> >> +    int i;
>> >> +
>> >> +    for (i = 0; i < panel_num; i++) {
>> >> +            if (index == dc->crtc[i]->base.index)
>> >> +                    return i;
>> >> +    }
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
>> >> +                                      unsigned int alignment)
>> >> +{
>> >> +    struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
>> >> +
>> >> +    if (alignment > priv->pitch_alignment)
>> >> +            priv->pitch_alignment = alignment;
>> >> +}
>> >> +
>> >> +static int plda_clk_rst_init(struct device *dev)
>> >> +{
>> >> +    int ret = 0;
>> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
>> >> +
>> >> +    ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
>> >> +    if (ret) {
>> >> +            dev_err(dev, "failed to enable clocks\n");
>> >> +            return ret;
>> >> +    }
>> >> +
>> >> +    ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
>> >> +    return ret;
>> >> +}
>> >> +
>> >> +static void plda_clk_rst_deinit(struct device *dev)
>> >> +{
>> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
>> >> +
>> >> +    reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
>> >> +    clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
>> >> +}
>> >> +
>> >> +static void dc_deinit(struct device *dev)
>> >> +{
>> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
>> >> +
>> >> +    dc_hw_enable_interrupt(&dc->hw, 0);
>> >> +    dc_hw_deinit(&dc->hw);
>> >> +    plda_clk_rst_deinit(dev);
>> >> +}
>> >> +
>> >> +static int dc_init(struct device *dev)
>> >> +{
>> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
>> >> +    int ret;
>> >> +
>> >> +    dc->first_frame = true;
>> >> +
>> >> +    ret = plda_clk_rst_init(dev);
>> >> +    if (ret < 0) {
>> >> +            dev_err(dev, "failed to init dc clk reset: %d\n", ret);
>> >> +            return ret;
>> >> +    }
>> >> +
>> >> +    ret = dc_hw_init(&dc->hw);
>> >> +    if (ret) {
>> >> +            dev_err(dev, "failed to init DC HW\n");
>> >> +            return ret;
>> >> +    }
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc)
>> >> +{
>> >> +    struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
>> >> +    struct drm_display_mode *mode = &crtc->state->adjusted_mode;
>> >> +    struct dc_hw_display display;
>> >> +
>> >> +    display.bus_format = crtc_state->output_fmt;
>> >> +    display.h_active = mode->hdisplay;
>> >> +    display.h_total = mode->htotal;
>> >> +    display.h_sync_start = mode->hsync_start;
>> >> +    display.h_sync_end = mode->hsync_end;
>> >> +    if (mode->flags & DRM_MODE_FLAG_PHSYNC)
>> >> +            display.h_sync_polarity = true;
>> >> +    else
>> >> +            display.h_sync_polarity = false;
>> >> +
>> >> +    display.v_active = mode->vdisplay;
>> >> +    display.v_total = mode->vtotal;
>> >> +    display.v_sync_start = mode->vsync_start;
>> >> +    display.v_sync_end = mode->vsync_end;
>> >> +
>> >> +    if (mode->flags & DRM_MODE_FLAG_PVSYNC)
>> >> +            display.v_sync_polarity = true;
>> >> +    else
>> >> +            display.v_sync_polarity = false;
>> >> +
>> >> +    display.id = to_vs_display_id(dc, crtc);
>> >> +
>> >> +    display.enable = true;
>> >> +
>> >> +    if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
>> >> +            dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
>> >> +            clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
>> >> +            clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
>> >> +                           dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
>> >> +    } else {
>> >> +            dc_hw_set_out(&dc->hw, OUT_DP, display.id);
>> >> +            clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
>> >> +                           dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
>> >> +    }
>> >> +
>> >> +    dc_hw_setup_display(&dc->hw, &display);
>> >> +}
>> >> +
>> >> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc)
>> >> +{
>> >> +    struct dc_hw_display display;
>> >> +
>> >> +    display.id = to_vs_display_id(dc, crtc);
>> >> +    display.enable = false;
>> >> +
>> >> +    dc_hw_setup_display(&dc->hw, &display);
>> >> +}
>> >> +
>> >> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
>> >> +                 struct drm_color_lut *lut, unsigned int size)
>> >> +{
>> >> +    u16 i, r, g, b;
>> >> +    u8 bits, id;
>> >> +
>> >> +    if (size != dc->hw.info->gamma_size) {
>> >> +            drm_err(crtc->dev, "gamma size does not match!\n");
>> >> +            return;
>> >> +    }
>> >> +
>> >> +    id = to_vs_display_id(dc, crtc);
>> >> +
>> >> +    bits = dc->hw.info->gamma_bits;
>> >> +    for (i = 0; i < size; i++) {
>> >> +            r = drm_color_lut_extract(lut[i].red, bits);
>> >> +            g = drm_color_lut_extract(lut[i].green, bits);
>> >> +            b = drm_color_lut_extract(lut[i].blue, bits);
>> >> +            dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
>> >> +    }
>> >> +}
>> >> +
>> >> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
>> >> +                    bool enable)
>> >> +{
>> >> +    u8 id;
>> >> +
>> >> +    id = to_vs_display_id(dc, crtc);
>> >> +    dc_hw_enable_gamma(&dc->hw, id, enable);
>> >> +}
>> >> +
>> >> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable)
>> >> +{
>> >> +    dc_hw_enable_interrupt(&dc->hw, enable);
>> >> +}
>> >> +
>> >> +static u32 calc_factor(u32 src, u32 dest)
>> >> +{
>> >> +    u32 factor = 1 << 16;
>> >> +
>> >> +    if (src > 1 && dest > 1)
>> >> +            factor = ((src - 1) << 16) / (dest - 1);
>> >> +
>> >> +    return factor;
>> >> +}
>> >> +
>> >> +static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
>> >> +                     struct dc_hw_scale *scale)
>> >> +{
>> >> +    int dst_w = drm_rect_width(&state->dst);
>> >> +    int dst_h = drm_rect_height(&state->dst);
>> >> +    int src_w, src_h, temp;
>> >> +
>> >> +    scale->enable = false;
>> >> +
>> >> +    if (roi->enable) {
>> >> +            src_w = roi->width;
>> >> +            src_h = roi->height;
>> >> +    } else {
>> >> +            src_w = drm_rect_width(&state->src) >> 16;
>> >> +            src_h = drm_rect_height(&state->src) >> 16;
>> >> +    }
>> >> +
>> >> +    if (drm_rotation_90_or_270(state->rotation)) {
>> >> +            temp = src_w;
>> >> +            src_w = src_h;
>> >> +            src_h = temp;
>> >> +    }
>> >> +
>> >> +    if (src_w != dst_w) {
>> >> +            scale->scale_factor_x = calc_factor(src_w, dst_w);
>> >> +            scale->enable = true;
>> >> +    } else {
>> >> +            scale->scale_factor_x = 1 << 16;
>> >> +    }
>> >> +    if (src_h != dst_h) {
>> >> +            scale->scale_factor_y = calc_factor(src_h, dst_h);
>> >> +            scale->enable = true;
>> >> +    } else {
>> >> +            scale->scale_factor_y = 1 << 16;
>> >> +    }
>> >> +}
>> >> +
>> >> +static void update_fb(struct vs_plane *plane, u8 display_id,
>> >> +                  struct dc_hw_fb *fb, struct drm_plane_state *state)
>> >> +{
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> >> +    struct drm_framebuffer *drm_fb = state->fb;
>> >> +    struct drm_rect *src = &state->src;
>> >> +
>> >> +    fb->display_id = display_id;
>> >> +    fb->y_address = plane_state->dma_addr[0];
>> >> +    fb->y_stride = drm_fb->pitches[0];
>> >> +    if (drm_fb->format->format == DRM_FORMAT_YVU420) {
>> >> +            fb->u_address = plane_state->dma_addr[2];
>> >> +            fb->v_address = plane_state->dma_addr[1];
>> >> +            fb->u_stride = drm_fb->pitches[2];
>> >> +            fb->v_stride = drm_fb->pitches[1];
>> >> +    } else {
>> >> +            fb->u_address = plane_state->dma_addr[1];
>> >> +            fb->v_address = plane_state->dma_addr[2];
>> >> +            fb->u_stride = drm_fb->pitches[1];
>> >> +            fb->v_stride = drm_fb->pitches[2];
>> >> +    }
>> >> +    fb->width = drm_rect_width(src) >> 16;
>> >> +    fb->height = drm_rect_height(src) >> 16;
>> >> +    fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
>> >> +    fb->rotation = to_vs_rotation(state->rotation);
>> >> +    fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
>> >> +    fb->zpos = state->zpos;
>> >> +    fb->enable = state->visible;
>> >> +    update_format(drm_fb->format->format, drm_fb->modifier, fb);
>> >> +    update_swizzle(drm_fb->format->format, fb);
>> >> +    update_watermark(plane_state->watermark, fb);
>> >> +    plane_state->status.tile_mode = fb->tile_mode;
>> >> +}
>> >> +
>> >> +static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                       struct vs_plane_state *plane_state)
>> >> +{
>> >> +    dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
>> >> +    plane_state->degamma_changed = false;
>> >> +}
>> >> +
>> >> +static void update_roi(struct vs_dc *dc, u8 id,
>> >> +                   struct vs_plane_state *plane_state,
>> >> +                   struct dc_hw_roi *roi,
>> >> +                   struct drm_plane_state *state)
>> >> +{
>> >> +    struct drm_vs_roi *data;
>> >> +    struct drm_rect *src = &state->src;
>> >> +    u16 src_w = drm_rect_width(src) >> 16;
>> >> +    u16 src_h = drm_rect_height(src) >> 16;
>> >> +
>> >> +    if (plane_state->roi) {
>> >> +            data = plane_state->roi->data;
>> >> +
>> >> +            if (data->enable) {
>> >> +                    roi->x = data->roi_x;
>> >> +                    roi->y = data->roi_y;
>> >> +                    roi->width = (data->roi_x + data->roi_w > src_w) ?
>> >> +                                             (src_w - data->roi_x) : data->roi_w;
>> >> +                    roi->height = (data->roi_y + data->roi_h > src_h) ?
>> >> +                                              (src_h - data->roi_y) : data->roi_h;
>> >> +                    roi->enable = true;
>> >> +            } else {
>> >> +                    roi->enable = false;
>> >> +            }
>> >> +
>> >> +            dc_hw_update_roi(&dc->hw, id, roi);
>> >> +    } else {
>> >> +            roi->enable = false;
>> >> +    }
>> >> +}
>> >> +
>> >> +static void update_color_mgmt(struct vs_dc *dc, u8 id,
>> >> +                          struct dc_hw_fb *fb,
>> >> +                          struct vs_plane_state *plane_state)
>> >> +{
>> >> +    struct drm_vs_color_mgmt *data;
>> >> +    struct dc_hw_colorkey colorkey;
>> >> +
>> >> +    if (plane_state->color_mgmt) {
>> >> +            data = plane_state->color_mgmt->data;
>> >> +
>> >> +            fb->clear_enable = data->clear_enable;
>> >> +            fb->clear_value = data->clear_value;
>> >> +
>> >> +            if (data->colorkey > data->colorkey_high)
>> >> +                    data->colorkey = data->colorkey_high;
>> >> +
>> >> +            colorkey.colorkey = data->colorkey;
>> >> +            colorkey.colorkey_high = data->colorkey_high;
>> >> +            colorkey.transparency = (data->transparency) ?
>> >> +                            DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
>> >> +            dc_hw_update_colorkey(&dc->hw, id, &colorkey);
>> >> +    }
>> >> +}
>> >> +
>> >> +static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                     struct drm_plane *drm_plane,
>> >> +                     struct drm_atomic_state *drm_state)
>> >> +{
>> >> +    struct dc_hw_fb fb = {0};
>> >> +    struct dc_hw_scale scale;
>> >> +    struct dc_hw_position pos;
>> >> +    struct dc_hw_blend blend;
>> >> +    struct dc_hw_roi roi;
>> >> +    struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
>> >> +                                                                       drm_plane);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> >> +    struct drm_rect *dest = &state->dst;
>> >> +    bool dec_enable = false;
>> >> +    u8 display_id = 0;
>> >> +
>> >> +    display_id = to_vs_display_id(dc, state->crtc);
>> >> +    update_fb(plane, display_id, &fb, state);
>> >> +    fb.dec_enable = dec_enable;
>> >> +
>> >> +    update_roi(dc, plane->id, plane_state, &roi, state);
>> >> +
>> >> +    update_scale(state, &roi, &scale);
>> >> +
>> >> +    if (plane_state->degamma_changed)
>> >> +            update_degamma(dc, plane, plane_state);
>> >> +
>> >> +    pos.start_x = dest->x1;
>> >> +    pos.start_y = dest->y1;
>> >> +    pos.end_x = dest->x2;
>> >> +    pos.end_y = dest->y2;
>> >> +
>> >> +    blend.alpha = (u8)(state->alpha >> 8);
>> >> +    blend.blend_mode = (u8)(state->pixel_blend_mode);
>> >> +
>> >> +    update_color_mgmt(dc, plane->id, &fb, plane_state);
>> >> +
>> >> +    dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
>> >> +}
>> >> +
>> >> +static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                   struct drm_plane *drm_plane,
>> >> +                   struct drm_atomic_state *drm_state)
>> >> +{
>> >> +    struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
>> >> +                                                                       drm_plane);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> >> +    struct drm_vs_watermark *data;
>> >> +    struct dc_hw_qos qos;
>> >> +
>> >> +    if (plane_state->watermark) {
>> >> +            data = plane_state->watermark->data;
>> >> +
>> >> +            if (data->qos_high) {
>> >> +                    if (data->qos_low > data->qos_high)
>> >> +                            data->qos_low = data->qos_high;
>> >> +
>> >> +                    qos.low_value = data->qos_low & 0x0F;
>> >> +                    qos.high_value = data->qos_high & 0x0F;
>> >> +                    dc_hw_update_qos(&dc->hw, &qos);
>> >> +            }
>> >> +    }
>> >> +}
>> >> +
>> >> +static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
>> >> +{
>> >> +    u8 size_type;
>> >> +
>> >> +    switch (state->crtc_w) {
>> >> +    case 32:
>> >> +            size_type = CURSOR_SIZE_32X32;
>> >> +            break;
>> >> +    case 64:
>> >> +            size_type = CURSOR_SIZE_64X64;
>> >> +            break;
>> >> +    default:
>> >> +            size_type = CURSOR_SIZE_32X32;
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    cursor->size = size_type;
>> >> +}
>> >> +
>> >> +static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                            struct drm_plane *drm_plane,
>> >> +                            struct drm_atomic_state *drm_state)
>> >> +{
>> >> +    struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
>> >> +                                                                   drm_plane);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(state);
>> >> +    struct drm_framebuffer *drm_fb = state->fb;
>> >> +    struct dc_hw_cursor cursor;
>> >> +
>> >> +    cursor.address = plane_state->dma_addr[0];
>> >> +    cursor.x = state->crtc_x;
>> >> +    cursor.y = state->crtc_y;
>> >> +    cursor.hot_x = drm_fb->hot_x;
>> >> +    cursor.hot_y = drm_fb->hot_y;
>> >> +    cursor.display_id = to_vs_display_id(dc, state->crtc);
>> >> +    update_cursor_size(state, &cursor);
>> >> +    cursor.enable = true;
>> >> +
>> >> +    dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
>> >> +}
>> >> +
>> >> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                    struct drm_plane *drm_plane,
>> >> +                    struct drm_atomic_state *drm_state)
>> >> +{
>> >> +    update_plane(dc, plane, drm_plane, drm_state);
>> >> +    update_qos(dc, plane, drm_plane, drm_state);
>> >> +}
>> >> +
>> >> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                           struct drm_plane *drm_plane,
>> >> +                           struct drm_atomic_state *drm_state)
>> >> +{
>> >> +    update_cursor_plane(dc, plane, drm_plane, drm_state);
>> >> +}
>> >> +
>> >> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                     struct drm_plane_state *old_state)
>> >> +{
>> >> +    struct dc_hw_fb fb = {0};
>> >> +
>> >> +    fb.enable = false;
>> >> +    dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
>> >> +}
>> >> +
>> >> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                            struct drm_plane_state *old_state)
>> >> +{
>> >> +    struct dc_hw_cursor cursor = {0};
>> >> +
>> >> +    cursor.enable = false;
>> >> +    cursor.display_id = to_vs_display_id(dc, old_state->crtc);
>> >> +    dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
>> >> +}
>> >> +
>> >> +static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
>> >> +                            u64 modifier)
>> >> +{
>> >> +    const u64 *mods;
>> >> +
>> >> +    if (!plane_info->modifiers)
>> >> +            return false;
>> >> +
>> >> +    for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
>> >> +            if (*mods == modifier)
>> >> +                    return true;
>> >> +    }
>> >> +
>> >> +    return false;
>> >> +}
>> >> +
>> >> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
>> >> +                  struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> >> +                                                                             plane);
>> >> +
>> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
>> >> +    const struct vs_plane_info *plane_info;
>> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
>> >> +    struct drm_crtc_state *crtc_state;
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +
>> >> +    plane_info = &dc->hw.info->planes[vs_plane->id];
>> >> +
>> >> +    if (fb->width < plane_info->min_width ||
>> >> +        fb->width > plane_info->max_width ||
>> >> +        fb->height < plane_info->min_height ||
>> >> +        fb->height > plane_info->max_height)
>> >> +            drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
>> >> +                         vs_plane->id);
>> >> +
>> >> +    if (!vs_dc_mod_supported(plane_info, fb->modifier)) {
>> >> +            drm_err(plane->dev, "unsupported modifier on plane%d.\n", vs_plane->id);
>> >> +            return -EINVAL;
>> >> +    }
>> >> +
>> >> +    crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
>> >> +    return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
>> >> +                                              plane_info->min_scale,
>> >> +                                              plane_info->max_scale,
>> >> +                                              true, true);
>> >> +}
>> >> +
>> >> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
>> >> +                         struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> >> +                                                                       plane);
>> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
>> >> +    const struct vs_plane_info *plane_info;
>> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
>> >> +    struct drm_crtc_state *crtc_state;
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +
>> >> +    plane_info = &dc->hw.info->planes[vs_plane->id];
>> >> +
>> >> +    if (fb->width < plane_info->min_width ||
>> >> +        fb->width > plane_info->max_width ||
>> >> +        fb->height < plane_info->min_height ||
>> >> +        fb->height > plane_info->max_height)
>> >> +            drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", vs_plane->id);
>> >> +
>> >> +    crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
>> >> +    if (IS_ERR(crtc_state))
>> >> +            return -EINVAL;
>> >> +
>> >> +    return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
>> >> +                                            plane_info->min_scale,
>> >> +                                            plane_info->max_scale,
>> >> +                                            true, true);
>> >> +}
>> >> +
>> >> +static void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
>> >> +{
>> >> +    struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
>> >> +
>> >> +    drm_crtc_handle_vblank(crtc);
>> >> +
>> >> +    vs_crtc_state->underflow = underflow;
>> >> +}
>> >> +
>> >> +static irqreturn_t dc_isr(int irq, void *data)
>> >> +{
>> >> +    struct vs_dc *dc = data;
>> >> +    struct vs_dc_info *dc_info = dc->hw.info;
>> >> +    u32 i, ret;
>> >> +
>> >> +    ret = dc_hw_get_interrupt(&dc->hw);
>> >> +
>> >> +    for (i = 0; i < dc_info->panel_num; i++)
>> >> +            vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
>> >> +
>> >> +    return IRQ_HANDLED;
>> >> +}
>> >> +
>> >> +void vs_dc_commit(struct vs_dc *dc)
>> >> +{
>> >> +    dc_hw_enable_shadow_register(&dc->hw, false);
>> >> +
>> >> +    dc_hw_commit(&dc->hw);
>> >> +
>> >> +    if (dc->first_frame)
>> >> +            dc->first_frame = false;
>> >> +
>> >> +    dc_hw_enable_shadow_register(&dc->hw, true);
>> >> +}
>> >> +
>> >> +static int dc_bind(struct device *dev, struct device *master, void *data)
>> >> +{
>> >> +    struct drm_device *drm_dev = data;
>> >> +    struct vs_dc *dc = dev_get_drvdata(dev);
>> >> +    struct device_node *port;
>> >> +    struct vs_crtc *crtc;
>> >> +    struct vs_dc_info *dc_info;
>> >> +    struct vs_plane *plane;
>> >> +    struct vs_plane_info *plane_info;
>> >> +    int i, ret;
>> >> +    u32 ctrc_mask = 0;
>> >> +
>> >> +    if (!drm_dev || !dc) {
>> >> +            dev_err(dev, "devices are not created.\n");
>> >> +            return -ENODEV;
>> >> +    }
>> >> +
>> >> +    ret = dc_init(dev);
>> >> +    if (ret < 0) {
>> >> +            drm_err(drm_dev, "Failed to initialize DC hardware.\n");
>> >> +            return ret;
>> >> +    }
>> >> +
>> >> +    port = of_get_child_by_name(dev->of_node, "port");
>> >> +    if (!port) {
>> >> +            drm_err(drm_dev, "no port node found\n");
>> >> +            return -ENODEV;
>> >> +    }
>> >> +    of_node_put(port);
>> >> +
>> >> +    dc_info = dc->hw.info;
>> >> +
>> >> +    for (i = 0; i < dc_info->panel_num; i++) {
>> >> +            crtc = vs_crtc_create(drm_dev, dc_info);
>> >> +            if (!crtc) {
>> >> +                    drm_err(drm_dev, "Failed to create CRTC.\n");
>> >> +                    ret = -ENOMEM;
>> >> +                    return ret;
>> >> +            }
>> >> +
>> >> +            crtc->base.port = port;
>> >> +            crtc->dev = dev;
>> >> +            dc->crtc[i] = crtc;
>> >> +            ctrc_mask |= drm_crtc_mask(&crtc->base);
>> >> +    }
>> >> +
>> >> +    for (i = 0; i < dc_info->plane_num; i++) {
>> >> +            plane_info = (struct vs_plane_info *)&dc_info->planes[i];
>> >> +
>> >> +            if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
>> >> +                    plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
>> >> +                                            drm_crtc_mask(&dc->crtc[0]->base));
>> >> +            } else if (!strcmp(plane_info->name, "Primary_1") ||
>> >> +                               !strcmp(plane_info->name, "Cursor_1")) {
>> >> +                    plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
>> >> +                                            drm_crtc_mask(&dc->crtc[1]->base));
>> >
>> > I'd say, it's not typical to use name to distinguish objects. Maybe you
>> > can add indices to the info structure and drop the names instead?
>> >
>> >
>> >> +            } else {
>> >> +                    plane = vs_plane_create(drm_dev, plane_info,
>> >> +                                            dc_info->layer_num, ctrc_mask);
>> >> +            }
>> >> +
>> >> +            if (IS_ERR(plane)) {
>> >> +                    dev_err(dev, "failed to construct plane\n");
>> >> +                    return PTR_ERR(plane);
>> >> +            }
>> >> +
>> >> +            plane->id = i;
>> >> +            dc->planes[i].id = plane_info->id;
>> >> +
>> >> +            if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
>> >> +                    if (!strcmp(plane_info->name, "Primary"))
>> >> +                            dc->crtc[0]->base.primary = &plane->base;
>> >> +                    else
>> >> +                            dc->crtc[1]->base.primary = &plane->base;
>> >
>> > This definitely urges for an index in the plane info / plane_state.
>> >
>> >> +                    drm_dev->mode_config.min_width = plane_info->min_width;
>> >> +                    drm_dev->mode_config.min_height =
>> >> +                                                    plane_info->min_height;
>> >> +                    drm_dev->mode_config.max_width = plane_info->max_width;
>> >> +                    drm_dev->mode_config.max_height =
>> >> +                                                    plane_info->max_height;
>> >> +            }
>> >> +
>> >> +            if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
>> >> +                    if (!strcmp(plane_info->name, "Cursor"))
>> >> +                            dc->crtc[0]->base.cursor = &plane->base;
>> >> +                    else
>> >> +                            dc->crtc[1]->base.cursor = &plane->base;
>> >> +                    drm_dev->mode_config.cursor_width =
>> >> +                                                    plane_info->max_width;
>> >> +                    drm_dev->mode_config.cursor_height =
>> >> +                                                    plane_info->max_height;
>> >> +            }
>> >> +    }
>> >> +
>> >> +    vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static void dc_unbind(struct device *dev, struct device *master, void *data)
>> >> +{
>> >> +    dc_deinit(dev);
>> >> +}
>> >> +
>> >> +const struct component_ops dc_component_ops = {
>> >> +    .bind = dc_bind,
>> >> +    .unbind = dc_unbind,
>> >> +};
>> >> +
>> >> +static const struct of_device_id dc_driver_dt_match[] = {
>> >> +    { .compatible = "starfive,jh7110-dc8200", },
>> >> +    {},
>> >> +};
>> >> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
>> >> +
>> >> +static int dc_probe(struct platform_device *pdev)
>> >> +{
>> >> +    struct device *dev = &pdev->dev;
>> >> +    struct vs_dc *dc;
>> >> +    int irq, ret, i;
>> >> +
>> >> +    dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
>> >> +    if (!dc)
>> >> +            return -ENOMEM;
>> >> +
>> >> +    dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
>> >> +    if (IS_ERR(dc->hw.hi_base))
>> >> +            return PTR_ERR(dc->hw.hi_base);
>> >> +
>> >> +    dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
>> >> +    if (IS_ERR(dc->hw.reg_base))
>> >> +            return PTR_ERR(dc->hw.reg_base);
>> >> +
>> >> +    dc->nclks = ARRAY_SIZE(dc->clk_vout);
>> >> +    for (i = 0; i < dc->nclks; ++i)
>> >> +            dc->clk_vout[i].id = vout_clocks[i];
>> >> +    ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
>> >> +    if (ret) {
>> >> +            dev_err(dev, "Failed to get clk controls\n");
>> >> +            return ret;
>> >> +    }
>> >> +
>> >> +    dc->nrsts = ARRAY_SIZE(dc->rst_vout);
>> >> +    for (i = 0; i < dc->nrsts; ++i)
>> >> +            dc->rst_vout[i].id = vout_resets[i];
>> >> +    ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
>> >> +                                             dc->rst_vout);
>> >> +    if (ret) {
>> >> +            dev_err(dev, "Failed to get reset controls\n");
>> >> +            return ret;
>> >> +    }
>> >> +
>> >> +    irq = platform_get_irq(pdev, 0);
>> >> +
>> >> +    ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
>> >
>> > Are you ready to handle the IRQ at this point?
Do you have some good suggestions?
Are there any hidden dangers in doing so?
Hope to get good opinions 

>> >
>> >> +    if (ret < 0) {
>> >> +            dev_err(dev, "Failed to install irq:%u.\n", irq);
>> >> +            return ret;
>> >> +    }
>> >> +
>> >> +    dev_set_drvdata(dev, dc);
>> >> +
>> >> +    return component_add(dev, &dc_component_ops);
>> >> +}
>> >> +
>> >> +static int dc_remove(struct platform_device *pdev)
>> >> +{
>> >> +    struct device *dev = &pdev->dev;
>> >> +
>> >> +    component_del(dev, &dc_component_ops);
>> >> +
>> >> +    dev_set_drvdata(dev, NULL);
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +struct platform_driver dc_platform_driver = {
>> >> +    .probe = dc_probe,
>> >> +    .remove = dc_remove,
>> >> +    .driver = {
>> >> +            .name = "vs-dc",
>> >> +            .of_match_table = of_match_ptr(dc_driver_dt_match),
>> >> +    },
>> >> +};
>> >> +
>> >> +MODULE_AUTHOR("StarFive Corporation");
>> >> +MODULE_DESCRIPTION("VeriSilicon DC Driver");
>> >> +MODULE_LICENSE("GPL");
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
>> >> new file mode 100644
>> >> index 000000000..8e96fd32c
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc.h
>> >> @@ -0,0 +1,80 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#ifndef __VS_DC_H__
>> >> +#define __VS_DC_H__
>> >> +
>> >> +#include <linux/clk.h>
>> >> +#include <linux/mm_types.h>
>> >> +#include <linux/reset.h>
>> >> +
>> >> +#include <drm/drm_fourcc.h>
>> >> +#include <drm/drm_modes.h>
>> >> +
>> >> +#include "vs_crtc.h"
>> >> +#include "vs_dc_hw.h"
>> >> +#include "vs_plane.h"
>> >> +
>> >> +struct vs_dc_plane {
>> >> +    enum dc_hw_plane_id id;
>> >> +};
>> >> +
>> >> +enum vout_clk {
>> >> +    CLK_VOUT_NOC_DISP = 0,
>> >> +    CLK_VOUT_PIX0,
>> >> +    CLK_VOUT_PIX1,
>> >> +    CLK_VOUT_CORE,
>> >> +    CLK_VOUT_AXI,
>> >> +    CLK_VOUT_AHB,
>> >> +    CLK_VOUT_HDMI_PIX,
>> >> +    CLK_VOUT_SOC_PIX,
>> >> +    CLK_VOUT_NUM
>> >> +};
>> >> +
>> >> +enum rst_vout {
>> >> +    RST_VOUT_AXI = 0,
>> >> +    RST_VOUT_AHB,
>> >> +    RST_VOUT_CORE,
>> >> +    RST_VOUT_NUM
>> >> +};
>> >> +
>> >> +struct vs_dc {
>> >> +    struct vs_crtc          *crtc[DC_DISPLAY_NUM];
>> >> +    struct dc_hw            hw;
>> >> +    bool                    first_frame;
>> >> +
>> >> +    struct vs_dc_plane      planes[PLANE_NUM];
>> >> +    struct clk_bulk_data    clk_vout[CLK_VOUT_NUM];
>> >> +    int                     nclks;
>> >> +    struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
>> >> +    int                     nrsts;
>> >> +};
>> >> +
>> >> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc);
>> >> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc);
>> >> +
>> >> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
>> >> +                 struct drm_color_lut *lut, unsigned int size);
>> >> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc, bool enable);
>> >> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable);
>> >> +void vs_dc_commit(struct vs_dc *dc);
>> >> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                    struct drm_plane *drm_plane,
>> >> +                    struct drm_atomic_state *drm_state);
>> >> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                     struct drm_plane_state *old_state);
>> >> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
>> >> +                  struct drm_atomic_state *state);
>> >> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                           struct drm_plane *drm_plane,
>> >> +                           struct drm_atomic_state *drm_state);
>> >> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
>> >> +                            struct drm_plane_state *old_state);
>> >> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
>> >> +                         struct drm_atomic_state *state);
>> >> +
>> >> +extern struct platform_driver dc_platform_driver;
>> >> +
>> >> +#endif /* __VS_DC_H__ */
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
>> >> new file mode 100644
>> >> index 000000000..e5acb7eb4
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
>> >> @@ -0,0 +1,1959 @@
>> >> +// SPDX-License-Identifier: GPL-2.0
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#include <linux/bits.h>
>> >> +#include <linux/io.h>
>> >> +#include <linux/media-bus-format.h>
>> >> +#include <drm/drm_atomic_helper.h>
>> >> +#include <drm/drm_blend.h>
>> >> +#include <drm/drm_fourcc.h>
>> >> +#include <drm/vs_drm.h>
>> >> +
>> >> +#include "vs_dc_hw.h"
>> >> +#include "vs_type.h"
>> >> +
>> >> +static const u32 horkernel[] = {
>> >> +    0x00000000, 0x20000000, 0x00002000, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x2b981468,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x10f00000,
>> >> +    0x00002f10, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x3781087f, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x06660000, 0x0000399a, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x01470000,
>> >> +    0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x00004000, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x20002000, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x14680000,
>> >> +    0x00002b98, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x087f0000, 0x00003781, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x399a0666, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x021f0000,
>> >> +};
>> >> +
>> >> +#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))
>> >> +
>> >> +static const u32 verkernel[] = {
>> >> +    0x00000000, 0x20000000, 0x00002000, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x2b981468,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x10f00000,
>> >> +    0x00002f10, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x3781087f, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x06660000, 0x0000399a, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
>> >> +    0x00000000, 0x00000000, 0x00000000, 0x01470000,
>> >> +    0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
>> >> +    0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
>> >> +    0x00000000, 0x00000000, 0x00004000, 0x00000000,
>> >> +    0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
>> >> +    0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
>> >> +    0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +    0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
>> >> +};
>> >> +
>> >> +#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))
>> >> +
>> >> +/*
>> >> + * RGB 709->2020 conversion parameters
>> >> + */
>> >> +static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
>> >> +    10279,  5395,   709,
>> >> +    1132,   15065,  187,
>> >> +    269,    1442,   14674
>> >> +};
>> >> +
>> >> +/*
>> >> + * YUV601 to RGB conversion parameters
>> >> + * YUV2RGB[0]  - [8] : C0 - C8;
>> >> + * YUV2RGB[9]  - [11]: D0 - D2;
>> >> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
>> >> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
>> >> + */
>> >> +static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
>> >> +    1196,   0,                      1640,   1196,
>> >> +    -404,   -836,           1196,   2076,
>> >> +    0,              -916224,        558336, -1202944,
>> >> +    64,              940,           64,             960
>> >> +};
>> >> +
>> >> +/*
>> >> + * YUV709 to RGB conversion parameters
>> >> + * YUV2RGB[0]  - [8] : C0 - C8;
>> >> + * YUV2RGB[9]  - [11]: D0 - D2;
>> >> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
>> >> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
>> >> + */
>> >> +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
>> >> +    1196,           0,              1844,   1196,
>> >> +    -220,           -548,   1196,   2172,
>> >> +    0,                      -1020672, 316672,  -1188608,
>> >> +    64,                     940,            64,             960
>> >> +};
>> >> +
>> >> +/*
>> >> + * YUV2020 to RGB conversion parameters
>> >> + * YUV2RGB[0]  - [8] : C0 - C8;
>> >> + * YUV2RGB[9]  - [11]: D0 - D2;
>> >> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
>> >> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
>> >> + */
>> >> +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
>> >> +    1196, 0, 1724, 1196,
>> >> +    -192, -668, 1196, 2200,
>> >> +    0, -959232, 363776, -1202944,
>> >> +    64, 940, 64, 960
>> >> +};
>> >> +
>> >> +/*
>> >> + * RGB to YUV2020 conversion parameters
>> >> + * RGB2YUV[0] - [8] : C0 - C8;
>> >> + * RGB2YUV[9] - [11]: D0 - D2;
>> >> + */
>> >> +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
>> >> +    230,    594,    52,
>> >> +    -125,  -323,    448,
>> >> +    448,   -412,   -36,
>> >> +    64,             512,    512
>> >> +};
>> >> +
>> >> +/*
>> >> + * Degamma table for 709 color space data.
>> >> + */
>> >> +static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
>> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
>> >> +    0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
>> >> +    0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
>> >> +    0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
>> >> +    0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
>> >> +    0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
>> >> +    0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
>> >> +    0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
>> >> +    0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
>> >> +    0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
>> >> +    0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
>> >> +    0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
>> >> +    0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
>> >> +    0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
>> >> +    0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
>> >> +    0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
>> >> +    0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
>> >> +    0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
>> >> +    0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
>> >> +    0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
>> >> +    0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
>> >> +    0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
>> >> +    0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
>> >> +    0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
>> >> +    0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
>> >> +    0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
>> >> +    0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
>> >> +    0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
>> >> +    0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
>> >> +    0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
>> >> +    0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
>> >> +    0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
>> >> +    0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
>> >> +};
>> >> +
>> >> +/*
>> >> + * Degamma table for 2020 color space data.
>> >> + */
>> >> +static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
>> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
>> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
>> >> +    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
>> >> +    0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
>> >> +    0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
>> >> +    0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
>> >> +    0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
>> >> +    0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
>> >> +    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
>> >> +    0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
>> >> +    0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
>> >> +    0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
>> >> +    0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
>> >> +    0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
>> >> +    0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
>> >> +    0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
>> >> +    0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
>> >> +    0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
>> >> +    0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
>> >> +    0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
>> >> +    0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
>> >> +    0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
>> >> +    0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
>> >> +    0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
>> >> +    0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
>> >> +    0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
>> >> +    0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
>> >> +    0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
>> >> +    0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
>> >> +    0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
>> >> +    0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
>> >> +    0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
>> >> +    0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
>> >> +};
>> >> +
>> >> +/* one is for primary plane and the other is for all overlay planes */
>> >> +static const struct dc_hw_plane_reg dc_plane_reg[] = {
>> >> +    {
>> >> +    .y_address              = DC_FRAMEBUFFER_ADDRESS,
>> >> +    .u_address              = DC_FRAMEBUFFER_U_ADDRESS,
>> >> +    .v_address              = DC_FRAMEBUFFER_V_ADDRESS,
>> >> +    .y_stride               = DC_FRAMEBUFFER_STRIDE,
>> >> +    .u_stride               = DC_FRAMEBUFFER_U_STRIDE,
>> >> +    .v_stride               = DC_FRAMEBUFFER_V_STRIDE,
>> >> +    .size                   = DC_FRAMEBUFFER_SIZE,
>> >> +    .top_left               = DC_FRAMEBUFFER_TOP_LEFT,
>> >> +    .bottom_right   = DC_FRAMEBUFFER_BOTTOM_RIGHT,
>> >> +    .scale_factor_x                 = DC_FRAMEBUFFER_SCALE_FACTOR_X,
>> >> +    .scale_factor_y                 = DC_FRAMEBUFFER_SCALE_FACTOR_Y,
>> >> +    .h_filter_coef_index    = DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
>> >> +    .h_filter_coef_data             = DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
>> >> +    .v_filter_coef_index    = DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
>> >> +    .v_filter_coef_data             = DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
>> >> +    .init_offset                    = DC_FRAMEBUFFER_INIT_OFFSET,
>> >> +    .color_key                              = DC_FRAMEBUFFER_COLOR_KEY,
>> >> +    .color_key_high                 = DC_FRAMEBUFFER_COLOR_KEY_HIGH,
>> >> +    .clear_value                    = DC_FRAMEBUFFER_CLEAR_VALUE,
>> >> +    .color_table_index              = DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
>> >> +    .color_table_data               = DC_FRAMEBUFFER_COLOR_TABLE_DATA,
>> >> +    .scale_config                   = DC_FRAMEBUFFER_SCALE_CONFIG,
>> >> +    .water_mark                             = DC_FRAMEBUFFER_WATER_MARK,
>> >> +    .degamma_index                  = DC_FRAMEBUFFER_DEGAMMA_INDEX,
>> >> +    .degamma_data                   = DC_FRAMEBUFFER_DEGAMMA_DATA,
>> >> +    .degamma_ex_data                = DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
>> >> +    .src_global_color               = DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
>> >> +    .dst_global_color               = DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
>> >> +    .blend_config                   = DC_FRAMEBUFFER_BLEND_CONFIG,
>> >> +    .roi_origin                             = DC_FRAMEBUFFER_ROI_ORIGIN,
>> >> +    .roi_size                               = DC_FRAMEBUFFER_ROI_SIZE,
>> >> +    .yuv_to_rgb_coef0                       = DC_FRAMEBUFFER_YUVTORGB_COEF0,
>> >> +    .yuv_to_rgb_coef1                       = DC_FRAMEBUFFER_YUVTORGB_COEF1,
>> >> +    .yuv_to_rgb_coef2                       = DC_FRAMEBUFFER_YUVTORGB_COEF2,
>> >> +    .yuv_to_rgb_coef3                       = DC_FRAMEBUFFER_YUVTORGB_COEF3,
>> >> +    .yuv_to_rgb_coef4                       = DC_FRAMEBUFFER_YUVTORGB_COEF4,
>> >> +    .yuv_to_rgb_coefd0                      = DC_FRAMEBUFFER_YUVTORGB_COEFD0,
>> >> +    .yuv_to_rgb_coefd1                      = DC_FRAMEBUFFER_YUVTORGB_COEFD1,
>> >> +    .yuv_to_rgb_coefd2                      = DC_FRAMEBUFFER_YUVTORGB_COEFD2,
>> >> +    .y_clamp_bound                          = DC_FRAMEBUFFER_Y_CLAMP_BOUND,
>> >> +    .uv_clamp_bound                         = DC_FRAMEBUFFER_UV_CLAMP_BOUND,
>> >> +    .rgb_to_rgb_coef0                       = DC_FRAMEBUFFER_RGBTORGB_COEF0,
>> >> +    .rgb_to_rgb_coef1                       = DC_FRAMEBUFFER_RGBTORGB_COEF1,
>> >> +    .rgb_to_rgb_coef2                       = DC_FRAMEBUFFER_RGBTORGB_COEF2,
>> >> +    .rgb_to_rgb_coef3                       = DC_FRAMEBUFFER_RGBTORGB_COEF3,
>> >> +    .rgb_to_rgb_coef4                       = DC_FRAMEBUFFER_RGBTORGB_COEF4,
>> >> +    },
>> >> +    {
>> >> +    .y_address              = DC_OVERLAY_ADDRESS,
>> >> +    .u_address              = DC_OVERLAY_U_ADDRESS,
>> >> +    .v_address              = DC_OVERLAY_V_ADDRESS,
>> >> +    .y_stride               = DC_OVERLAY_STRIDE,
>> >> +    .u_stride               = DC_OVERLAY_U_STRIDE,
>> >> +    .v_stride               = DC_OVERLAY_V_STRIDE,
>> >> +    .size                   = DC_OVERLAY_SIZE,
>> >> +    .top_left               = DC_OVERLAY_TOP_LEFT,
>> >> +    .bottom_right   = DC_OVERLAY_BOTTOM_RIGHT,
>> >> +    .scale_factor_x = DC_OVERLAY_SCALE_FACTOR_X,
>> >> +    .scale_factor_y = DC_OVERLAY_SCALE_FACTOR_Y,
>> >> +    .h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
>> >> +    .h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
>> >> +    .v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
>> >> +    .v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
>> >> +    .init_offset             = DC_OVERLAY_INIT_OFFSET,
>> >> +    .color_key                       = DC_OVERLAY_COLOR_KEY,
>> >> +    .color_key_high                 = DC_OVERLAY_COLOR_KEY_HIGH,
>> >> +    .clear_value             = DC_OVERLAY_CLEAR_VALUE,
>> >> +    .color_table_index       = DC_OVERLAY_COLOR_TABLE_INDEX,
>> >> +    .color_table_data        = DC_OVERLAY_COLOR_TABLE_DATA,
>> >> +    .scale_config            = DC_OVERLAY_SCALE_CONFIG,
>> >> +    .water_mark                             = DC_OVERLAY_WATER_MARK,
>> >> +    .degamma_index           = DC_OVERLAY_DEGAMMA_INDEX,
>> >> +    .degamma_data            = DC_OVERLAY_DEGAMMA_DATA,
>> >> +    .degamma_ex_data         = DC_OVERLAY_DEGAMMA_EX_DATA,
>> >> +    .src_global_color        = DC_OVERLAY_SRC_GLOBAL_COLOR,
>> >> +    .dst_global_color        = DC_OVERLAY_DST_GLOBAL_COLOR,
>> >> +    .blend_config            = DC_OVERLAY_BLEND_CONFIG,
>> >> +    .roi_origin                             = DC_OVERLAY_ROI_ORIGIN,
>> >> +    .roi_size                               = DC_OVERLAY_ROI_SIZE,
>> >> +    .yuv_to_rgb_coef0                = DC_OVERLAY_YUVTORGB_COEF0,
>> >> +    .yuv_to_rgb_coef1                = DC_OVERLAY_YUVTORGB_COEF1,
>> >> +    .yuv_to_rgb_coef2                = DC_OVERLAY_YUVTORGB_COEF2,
>> >> +    .yuv_to_rgb_coef3                = DC_OVERLAY_YUVTORGB_COEF3,
>> >> +    .yuv_to_rgb_coef4                       = DC_OVERLAY_YUVTORGB_COEF4,
>> >> +    .yuv_to_rgb_coefd0                      = DC_OVERLAY_YUVTORGB_COEFD0,
>> >> +    .yuv_to_rgb_coefd1                      = DC_OVERLAY_YUVTORGB_COEFD1,
>> >> +    .yuv_to_rgb_coefd2                      = DC_OVERLAY_YUVTORGB_COEFD2,
>> >> +    .y_clamp_bound           = DC_OVERLAY_Y_CLAMP_BOUND,
>> >> +    .uv_clamp_bound          = DC_OVERLAY_UV_CLAMP_BOUND,
>> >> +    .rgb_to_rgb_coef0                = DC_OVERLAY_RGBTORGB_COEF0,
>> >> +    .rgb_to_rgb_coef1                = DC_OVERLAY_RGBTORGB_COEF1,
>> >> +    .rgb_to_rgb_coef2                = DC_OVERLAY_RGBTORGB_COEF2,
>> >> +    .rgb_to_rgb_coef3                = DC_OVERLAY_RGBTORGB_COEF3,
>> >> +    .rgb_to_rgb_coef4                = DC_OVERLAY_RGBTORGB_COEF4,
>> >> +    },
>> >> +};
>> >> +
>> >> +static const u32 primary_overlay_format0[] = {
>> >> +    DRM_FORMAT_XRGB4444,
>> >> +    DRM_FORMAT_XBGR4444,
>> >> +    DRM_FORMAT_RGBX4444,
>> >> +    DRM_FORMAT_BGRX4444,
>> >> +    DRM_FORMAT_ARGB4444,
>> >> +    DRM_FORMAT_ABGR4444,
>> >> +    DRM_FORMAT_RGBA4444,
>> >> +    DRM_FORMAT_BGRA4444,
>> >> +    DRM_FORMAT_XRGB1555,
>> >> +    DRM_FORMAT_XBGR1555,
>> >> +    DRM_FORMAT_RGBX5551,
>> >> +    DRM_FORMAT_BGRX5551,
>> >> +    DRM_FORMAT_ARGB1555,
>> >> +    DRM_FORMAT_ABGR1555,
>> >> +    DRM_FORMAT_RGBA5551,
>> >> +    DRM_FORMAT_BGRA5551,
>> >> +    DRM_FORMAT_RGB565,
>> >> +    DRM_FORMAT_BGR565,
>> >> +    DRM_FORMAT_XRGB8888,
>> >> +    DRM_FORMAT_XBGR8888,
>> >> +    DRM_FORMAT_RGBX8888,
>> >> +    DRM_FORMAT_BGRX8888,
>> >> +    DRM_FORMAT_ARGB8888,
>> >> +    DRM_FORMAT_ABGR8888,
>> >> +    DRM_FORMAT_RGBA8888,
>> >> +    DRM_FORMAT_BGRA8888,
>> >> +    DRM_FORMAT_ARGB2101010,
>> >> +    DRM_FORMAT_ABGR2101010,
>> >> +    DRM_FORMAT_RGBA1010102,
>> >> +    DRM_FORMAT_BGRA1010102,
>> >> +    DRM_FORMAT_YUYV,
>> >> +    DRM_FORMAT_YVYU,
>> >> +    DRM_FORMAT_UYVY,
>> >> +    DRM_FORMAT_VYUY,
>> >> +    DRM_FORMAT_YVU420,
>> >> +    DRM_FORMAT_YUV420,
>> >> +    DRM_FORMAT_NV12,
>> >> +    DRM_FORMAT_NV21,
>> >> +    DRM_FORMAT_NV16,
>> >> +    DRM_FORMAT_NV61,
>> >> +    DRM_FORMAT_P010,
>> >> +};
>> >> +
>> >> +static const u32 primary_overlay_format1[] = {
>> >> +    DRM_FORMAT_XRGB8888,
>> >> +    DRM_FORMAT_XBGR8888,
>> >> +    DRM_FORMAT_RGBX8888,
>> >> +    DRM_FORMAT_BGRX8888,
>> >> +    DRM_FORMAT_ARGB8888,
>> >> +    DRM_FORMAT_ABGR8888,
>> >> +    DRM_FORMAT_RGBA8888,
>> >> +    DRM_FORMAT_BGRA8888,
>> >> +    DRM_FORMAT_ARGB2101010,
>> >> +    DRM_FORMAT_ABGR2101010,
>> >> +    DRM_FORMAT_RGBA1010102,
>> >> +    DRM_FORMAT_BGRA1010102,
>> >> +    DRM_FORMAT_NV12,
>> >> +    DRM_FORMAT_NV21,
>> >> +    DRM_FORMAT_YUV444,
>> >> +};
>> >> +
>> >> +static const u32 cursor_formats[] = {
>> >> +    DRM_FORMAT_ARGB8888
>> >> +};
>> >> +
>> >> +static const u64 format_modifier0[] = {
>> >> +    DRM_FORMAT_MOD_LINEAR,
>> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X8),
>> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_8X8),
>> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X8),
>> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X4),
>> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X4),
>> >> +    fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_4X8),
>> >> +    DRM_FORMAT_MOD_INVALID
>> >> +};
>> >> +
>> >> +static const u64 secondary_format_modifiers[] = {
>> >> +    DRM_FORMAT_MOD_LINEAR,
>> >> +    DRM_FORMAT_MOD_INVALID
>> >> +};
>> >> +
>> >> +#define FRAC_16_16(mult, div)        (((mult) << 16) / (div))
>> >> +
>> >> +static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {
>> >> +    {
>> >> +            /* DC_REV_0 */
>> >> +            {
>> >> +            .name                   = "Primary",
>> >
>> > I'd say that the indentation is strange here.
>> > It might be more scalable to split a single array into per-generation
>> > data structures and reference them directly from the info struct.
yes 
Use plat_data to reference
>> >
>> >> +            .id                             = PRIMARY_PLANE_0,
>> >> +            .type                   = DRM_PLANE_TYPE_PRIMARY,
>> >> +            .num_formats    = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats                = primary_overlay_format0,
>> >> +            .num_modifiers  = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers              = format_modifier0,
>> >> +            .min_width              = 0,
>> >> +            .min_height             = 0,
>> >> +            .max_width              = 4096,
>> >> +            .max_height             = 4096,
>> >> +            .rotation               = DRM_MODE_ROTATE_0 |
>> >> +                                                    DRM_MODE_ROTATE_90 |
>> >> +                                                    DRM_MODE_ROTATE_180 |
>> >> +                                                    DRM_MODE_ROTATE_270 |
>> >> +                                                    DRM_MODE_REFLECT_X |
>> >> +                                                    DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode             = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                                    BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                                    BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 0,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name                   = "Overlay",
>> >> +            .id                             = OVERLAY_PLANE_0,
>> >> +            .type                   = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats    = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats                = primary_overlay_format0,
>> >> +            .num_modifiers  = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers              = format_modifier0,
>> >> +            .min_width              = 0,
>> >> +            .min_height             = 0,
>> >> +            .max_width              = 4096,
>> >> +            .max_height             = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 1,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name                   = "Overlay_1",
>> >> +            .id                             = OVERLAY_PLANE_1,
>> >> +            .type                   = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats    = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats                = primary_overlay_format0,
>> >> +            .num_modifiers  = ARRAY_SIZE(secondary_format_modifiers),
>> >> +            .modifiers              = secondary_format_modifiers,
>> >> +            .min_width              = 0,
>> >> +            .min_height             = 0,
>> >> +            .max_width              = 4096,
>> >> +            .max_height             = 4096,
>> >> +            .rotation               = 0,
>> >> +            .blend_mode             = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                                    BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                                    BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 2,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Primary_1",
>> >> +            .id                             = PRIMARY_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 3,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay_2",
>> >> +            .id                             = OVERLAY_PLANE_2,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 4,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay_3",
>> >> +            .id                     = OVERLAY_PLANE_3,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
>> >> +            .modifiers       = secondary_format_modifiers,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = 0,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 5,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Cursor",
>> >> +            .id                             = CURSOR_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
>> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
>> >> +            .formats         = cursor_formats,
>> >> +            .num_modifiers = 0,
>> >> +            .modifiers       = NULL,
>> >> +            .min_width       = 32,
>> >> +            .min_height  = 32,
>> >> +            .max_width       = 64,
>> >> +            .max_height  = 64,
>> >> +            .rotation        = 0,
>> >> +            .degamma_size = 0,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 255,
>> >> +            .watermark       = false,
>> >> +            .color_mgmt  = false,
>> >> +            .roi             = false,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Cursor_1",
>> >> +            .id                             = CURSOR_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
>> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
>> >> +            .formats         = cursor_formats,
>> >> +            .num_modifiers = 0,
>> >> +            .modifiers       = NULL,
>> >> +            .min_width       = 32,
>> >> +            .min_height  = 32,
>> >> +            .max_width       = 64,
>> >> +            .max_height  = 64,
>> >> +            .rotation        = 0,
>> >> +            .degamma_size = 0,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 255,
>> >> +            .watermark       = false,
>> >> +            .color_mgmt  = false,
>> >> +            .roi             = false,
>> >> +            },
>> >> +    },
>> >> +    {
>> >> +            /* DC_REV_1 */
>> >> +            {
>> >> +            .name            = "Primary",
>> >> +            .id                             = PRIMARY_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 0,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay",
>> >> +            .id                             = OVERLAY_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 1,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Primary_1",
>> >> +            .id                             = PRIMARY_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 2,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay_2",
>> >> +            .id                             = OVERLAY_PLANE_2,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format0),
>> >> +            .formats         = primary_overlay_format0,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 3,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Cursor",
>> >> +            .id                             = CURSOR_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
>> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
>> >> +            .formats         = cursor_formats,
>> >> +            .num_modifiers = 0,
>> >> +            .modifiers       = NULL,
>> >> +            .min_width       = 32,
>> >> +            .min_height  = 32,
>> >> +            .max_width       = 64,
>> >> +            .max_height  = 64,
>> >> +            .rotation        = 0,
>> >> +            .degamma_size = 0,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 255,
>> >> +            .watermark       = false,
>> >> +            .color_mgmt  = false,
>> >> +            .roi             = false,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Cursor_1",
>> >> +            .id                             = CURSOR_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
>> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
>> >> +            .formats         = cursor_formats,
>> >> +            .num_modifiers = 0,
>> >> +            .modifiers       = NULL,
>> >> +            .min_width       = 32,
>> >> +            .min_height  = 32,
>> >> +            .max_width       = 64,
>> >> +            .max_height  = 64,
>> >> +            .rotation        = 0,
>> >> +            .degamma_size = 0,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 255,
>> >> +            .watermark       = false,
>> >> +            .color_mgmt  = false,
>> >> +            .roi             = false,
>> >> +            },
>> >> +    },
>> >> +    {
>> >> +            /* DC_REV_2 */
>> >> +            {
>> >> +            .name            = "Primary",
>> >> +            .id                             = PRIMARY_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
>> >> +            .formats         = primary_overlay_format1,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 0,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay",
>> >> +            .id                             = OVERLAY_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
>> >> +            .formats         = primary_overlay_format1,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 1,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay_1",
>> >> +            .id                             = OVERLAY_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
>> >> +            .formats         = primary_overlay_format1,
>> >> +            .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
>> >> +            .modifiers       = secondary_format_modifiers,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = 0,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 2,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Primary_1",
>> >> +            .id                             = PRIMARY_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_PRIMARY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
>> >> +            .formats         = primary_overlay_format1,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 3,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay_2",
>> >> +            .id                             = OVERLAY_PLANE_2,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
>> >> +            .formats         = primary_overlay_format1,
>> >> +            .num_modifiers = ARRAY_SIZE(format_modifier0),
>> >> +            .modifiers       = format_modifier0,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = DRM_MODE_ROTATE_0 |
>> >> +                                       DRM_MODE_ROTATE_90 |
>> >> +                                       DRM_MODE_ROTATE_180 |
>> >> +                                       DRM_MODE_ROTATE_270 |
>> >> +                                       DRM_MODE_REFLECT_X |
>> >> +                                       DRM_MODE_REFLECT_Y,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = FRAC_16_16(1, 3),
>> >> +            .max_scale       = FRAC_16_16(10, 1),
>> >> +            .zpos            = 4,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Overlay_3",
>> >> +            .id                             = OVERLAY_PLANE_3,
>> >> +            .type            = DRM_PLANE_TYPE_OVERLAY,
>> >> +            .num_formats = ARRAY_SIZE(primary_overlay_format1),
>> >> +            .formats         = primary_overlay_format1,
>> >> +            .num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
>> >> +            .modifiers       = secondary_format_modifiers,
>> >> +            .min_width       = 0,
>> >> +            .min_height  = 0,
>> >> +            .max_width       = 4096,
>> >> +            .max_height  = 4096,
>> >> +            .rotation        = 0,
>> >> +            .blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>> >> +                                       BIT(DRM_MODE_BLEND_PREMULTI) |
>> >> +                                       BIT(DRM_MODE_BLEND_COVERAGE),
>> >> +            .color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
>> >> +                                              BIT(DRM_COLOR_YCBCR_BT2020),
>> >> +            .degamma_size   = DEGAMMA_SIZE,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 5,
>> >> +            .watermark       = true,
>> >> +            .color_mgmt  = true,
>> >> +            .roi             = true,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Cursor",
>> >> +            .id                             = CURSOR_PLANE_0,
>> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
>> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
>> >> +            .formats         = cursor_formats,
>> >> +            .num_modifiers = 0,
>> >> +            .modifiers       = NULL,
>> >> +            .min_width       = 32,
>> >> +            .min_height  = 32,
>> >> +            .max_width       = 64,
>> >> +            .max_height  = 64,
>> >> +            .rotation        = 0,
>> >> +            .degamma_size = 0,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 255,
>> >> +            .watermark       = false,
>> >> +            .color_mgmt  = false,
>> >> +            .roi             = false,
>> >> +            },
>> >> +            {
>> >> +            .name            = "Cursor_1",
>> >> +            .id                             = CURSOR_PLANE_1,
>> >> +            .type            = DRM_PLANE_TYPE_CURSOR,
>> >> +            .num_formats = ARRAY_SIZE(cursor_formats),
>> >> +            .formats         = cursor_formats,
>> >> +            .num_modifiers = 0,
>> >> +            .modifiers       = NULL,
>> >> +            .min_width       = 32,
>> >> +            .min_height  = 32,
>> >> +            .max_width       = 64,
>> >> +            .max_height  = 64,
>> >> +            .rotation        = 0,
>> >> +            .degamma_size = 0,
>> >> +            .min_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .max_scale       = DRM_PLANE_NO_SCALING,
>> >> +            .zpos            = 255,
>> >> +            .watermark       = false,
>> >> +            .color_mgmt  = false,
>> >> +            .roi             = false,
>> >> +            },
>> >> +    },
>> >> +};
>> >> +
>> >> +static const struct vs_dc_info dc_info[] = {
>> >
>> > Again, please split into per-generation instances.
will add  per-generation instances data
and I will only keep DC_REV_0 data struct
DC_REV_1 DC_REV_2 will delete ,because only DC_REV_0 used
>> >
>> >> +    {
>> >> +            /* DC_REV_0 */
>> >> +            .name                   = "DC8200",
>> >> +            .panel_num              = 2,
>> >> +            .plane_num              = 8,
>> >> +            .planes                 = dc_hw_planes[DC_REV_0],
>> >> +            .layer_num              = 6,
>> >> +            .max_bpc                = 10,
>> >> +            .color_formats  = DRM_COLOR_FORMAT_RGB444 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR444 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR422 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR420,
>> >> +            .gamma_size             = GAMMA_EX_SIZE,
>> >> +            .gamma_bits             = 12,
>> >> +            .pitch_alignment        = 128,
>> >> +            .pipe_sync              = false,
>> >> +            .background             = true,
>> >> +            .panel_sync             = true,
>> >> +            .cap_dec                = true,
>> >> +    },
>> >> +    {
>> >> +            /* DC_REV_1 */
>> >> +            .name                   = "DC8200",
>> >> +            .panel_num              = 2,
>> >> +            .plane_num              = 6,
>> >> +            .planes                 = dc_hw_planes[DC_REV_1],
>> >> +            .layer_num              = 4,
>> >> +            .max_bpc                = 10,
>> >> +            .color_formats  = DRM_COLOR_FORMAT_RGB444 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR444 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR422 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR420,
>> >> +            .gamma_size             = GAMMA_EX_SIZE,
>> >> +            .gamma_bits             = 12,
>> >> +            .pitch_alignment        = 128,
>> >> +            .pipe_sync              = false,
>> >> +            .background             = true,
>> >> +            .panel_sync             = true,
>> >> +            .cap_dec                = true,
>> >> +    },
>> >> +    {
>> >> +            /* DC_REV_2 */
>> >> +            .name                   = "DC8200",
>> >> +            .panel_num              = 2,
>> >> +            .plane_num              = 8,
>> >> +            .planes                 = dc_hw_planes[DC_REV_2],
>> >> +            .layer_num              = 6,
>> >> +            .max_bpc                = 10,
>> >> +            .color_formats  = DRM_COLOR_FORMAT_RGB444 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR444 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR422 |
>> >> +                                              DRM_COLOR_FORMAT_YCBCR420,
>> >> +            .gamma_size             = GAMMA_EX_SIZE,
>> >> +            .gamma_bits             = 12,
>> >> +            .pitch_alignment        = 128,
>> >> +            .pipe_sync              = false,
>> >> +            .background             = true,
>> >> +            .panel_sync             = true,
>> >> +            .cap_dec                = false,
>> >> +    },
>> >> +};
>> >> +
>> >> +static const struct dc_hw_funcs hw_func;
>> >> +
>> >> +static inline u32 hi_read(struct dc_hw *hw, u32 reg)
>> >> +{
>> >> +    return readl(hw->hi_base + reg);
>> >> +}
>> >> +
>> >> +static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
>> >> +{
>> >> +    writel(value, hw->hi_base + reg);
>> >> +}
>> >> +
>> >> +static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
>> >> +{
>> >> +    writel(value, hw->reg_base + reg - DC_REG_BASE);
>> >> +}
>> >> +
>> >> +static inline u32 dc_read(struct dc_hw *hw, u32 reg)
>> >> +{
>> >> +    u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
>> >> +
>> >> +    return value;
>> >> +}
>> >> +
>> >> +static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
>> >> +{
>> >> +    u32 value = dc_read(hw, reg);
>> >> +
>> >> +    value &= ~clear;
>> >> +    value |= set;
>> >> +    dc_write(hw, reg, value);
>> >> +}
>> >> +
>> >> +static void load_default_filter(struct dc_hw *hw,
>> >> +                            const struct dc_hw_plane_reg *reg, u32 offset)
>> >> +{
>> >> +    u8 i;
>> >> +
>> >> +    dc_write(hw, reg->scale_config + offset, 0x33);
>> >> +    dc_write(hw, reg->init_offset + offset, 0x80008000);
>> >> +    dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
>> >> +    for (i = 0; i < H_COEF_SIZE; i++)
>> >> +            dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
>> >> +
>> >> +    dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
>> >> +    for (i = 0; i < V_COEF_SIZE; i++)
>> >> +            dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
>> >> +}
>> >> +
>> >> +static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
>> >> +                        u32 offset, u16 *table)
>> >> +{
>> >> +    dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
>> >> +    dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
>> >> +    dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
>> >> +    dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
>> >> +    dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
>> >> +}
>> >> +
>> >> +static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
>> >> +                        u32 offset, s32 *table)
>> >> +{
>> >> +    dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
>> >> +             (0xFFFF & table[0]) | (table[1] << 16));
>> >> +    dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
>> >> +             (0xFFFF & table[2]) | (table[3] << 16));
>> >> +    dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
>> >> +             (0xFFFF & table[4]) | (table[5] << 16));
>> >> +    dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
>> >> +             (0xFFFF & table[6]) | (table[7] << 16));
>> >> +    dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
>> >> +    dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
>> >> +    dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
>> >> +    dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
>> >> +    dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
>> >> +    dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
>> >> +}
>> >> +
>> >> +static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
>> >> +{
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
>> >> +             table[0] | (table[1] << 16));
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
>> >> +             table[2] | (table[3] << 16));
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
>> >> +             table[4] | (table[5] << 16));
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
>> >> +             table[6] | (table[7] << 16));
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
>> >> +    dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
>> >> +}
>> >> +
>> >> +static bool is_rgb(enum dc_hw_color_format format)
>> >> +{
>> >> +    switch (format) {
>> >> +    case FORMAT_X4R4G4B4:
>> >> +    case FORMAT_A4R4G4B4:
>> >> +    case FORMAT_X1R5G5B5:
>> >> +    case FORMAT_A1R5G5B5:
>> >> +    case FORMAT_R5G6B5:
>> >> +    case FORMAT_X8R8G8B8:
>> >> +    case FORMAT_A8R8G8B8:
>> >> +    case FORMAT_A2R10G10B10:
>> >> +            return true;
>> >> +    default:
>> >> +            return false;
>> >> +    }
>> >> +}
>> >> +
>> >> +static void load_degamma_table(struct dc_hw *hw,
>> >> +                           const struct dc_hw_plane_reg *reg,
>> >> +                           u32 offset, u16 *table)
>> >> +{
>> >> +    u16 i;
>> >> +    u32 value;
>> >> +
>> >> +    dc_write(hw, reg->degamma_index + offset, 0);
>> >> +
>> >> +    for (i = 0; i < DEGAMMA_SIZE; i++) {
>> >> +            value = table[i] | (table[i] << 16);
>> >> +            dc_write(hw, reg->degamma_data + offset, value);
>> >> +            dc_write(hw, reg->degamma_ex_data + offset, table[i]);
>> >> +    }
>> >> +}
>> >> +
>> >> +static u32 get_addr_offset(u32 id)
>> >> +{
>> >> +    u32 offset = 0;
>> >> +
>> >> +    switch (id) {
>> >> +    case PRIMARY_PLANE_1:
>> >> +    case OVERLAY_PLANE_1:
>> >> +            offset = 0x04;
>> >> +            break;
>> >> +    case OVERLAY_PLANE_2:
>> >> +            offset = 0x08;
>> >> +            break;
>> >> +    case OVERLAY_PLANE_3:
>> >> +            offset = 0x0C;
>> >> +            break;
>> >> +    default:
>> >> +            break;
>> >> +    }
>> >> +
>> >> +    return offset;
>> >> +}
>> >> +
>> >> +int dc_hw_init(struct dc_hw *hw)
>> >> +{
>> >> +    u8 i, id, panel_num, layer_num;
>> >> +    u32 offset;
>> >> +    u32 revision = hi_read(hw, DC_HW_REVISION);
>> >> +    u32 cid = hi_read(hw, DC_HW_CHIP_CID);
>> >> +    const struct dc_hw_plane_reg *reg;
>> >> +
>> >> +    switch (revision) {
>> >> +    case 0x5720:
>> >> +            hw->rev = DC_REV_0;
>> >> +            break;
>> >> +    case 0x5721:
>> >> +            switch (cid) {
>> >> +            case 0x30B:
>> >> +                    hw->rev = DC_REV_1;
>> >> +                    break;
>> >> +            case 0x310:
>> >> +                    hw->rev = DC_REV_2;
>> >> +                    break;
>> >> +            default:
>> >> +                    hw->rev = DC_REV_0;
>> >> +                    break;
>> >> +            }
>> >> +            break;
>> >> +    default:
>> >> +            return -ENXIO;
>> >> +    }
>> >
>> > We (drm/msm) had code like this for a while (and autodetection of the HW
>> > ID). And nowadays we are migrating to of_device_get_match_data and
>> > per-SoC compat names. It is just easier to handle, it allows one to
>> > specify device more precisely and also it simplifies DT schema.
of_device_get_match_data is a good choice

>> >
>> >> +
>> >> +    hw->info = (struct vs_dc_info *)&dc_info[hw->rev];
>> >> +    hw->func = (struct dc_hw_funcs *)&hw_func;
>> >> +
>> >> +    layer_num = hw->info->layer_num;
>> >> +    for (i = 0; i < layer_num; i++) {
>> >> +            id = hw->info->planes[i].id;
>> >> +            offset = get_addr_offset(id);
>> >> +            if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
>> >> +                    reg = &dc_plane_reg[0];
>> >> +            else
>> >> +                    reg = &dc_plane_reg[1];
>> >> +
>> >> +            load_default_filter(hw, reg, offset);
>> >> +            load_rgb_to_rgb(hw, reg, offset, RGB2RGB);
>> >> +    }
>> >> +
>> >> +    panel_num = hw->info->panel_num;
>> >> +    for (i = 0; i < panel_num; i++) {
>> >> +            offset = i << 2;
>> >> +
>> >> +            load_rgb_to_yuv(hw, offset, RGB2YUV);
>> >> +            dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
>> >> +
>> >> +            offset = i ? DC_CURSOR_OFFSET : 0;
>> >> +            dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
>> >> +            dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
>> >> +    }
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +void dc_hw_deinit(struct dc_hw *hw)
>> >> +{
>> >> +    /* Nothing to do */
>> >> +}
>> >> +
>> >> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
>> >> +                    struct dc_hw_fb *fb, struct dc_hw_scale *scale,
>> >> +                    struct dc_hw_position *pos, struct dc_hw_blend *blend)
>> >> +{
>> >> +    struct dc_hw_plane *plane = &hw->plane[id];
>> >> +
>> >> +    if (plane) {
>> >> +            if (fb) {
>> >> +                    if (!fb->enable)
>> >> +                            plane->fb.enable = false;
>> >> +                    else
>> >> +                            memcpy(&plane->fb, fb,
>> >> +                                   sizeof(*fb) - sizeof(fb->dirty));
>> >> +                    plane->fb.dirty = true;
>> >> +            }
>> >> +            if (scale) {
>> >> +                    memcpy(&plane->scale, scale,
>> >> +                           sizeof(*scale) - sizeof(scale->dirty));
>> >> +                    plane->scale.dirty = true;
>> >> +            }
>> >> +            if (pos) {
>> >> +                    memcpy(&plane->pos, pos,
>> >> +                           sizeof(*pos) - sizeof(pos->dirty));
>> >> +                    plane->pos.dirty = true;
>> >> +            }
>> >> +            if (blend) {
>> >> +                    memcpy(&plane->blend, blend,
>> >> +                           sizeof(*blend) - sizeof(blend->dirty));
>> >> +                    plane->blend.dirty = true;
>> >> +            }
>> >> +    }
>> >> +}
>> >> +
>> >> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode)
>> >> +{
>> >> +    struct dc_hw_plane *plane = &hw->plane[id];
>> >> +
>> >> +    if (plane) {
>> >> +            if (hw->info->planes[id].degamma_size) {
>> >> +                    plane->degamma.mode = mode;
>> >> +                    plane->degamma.dirty = true;
>> >> +            } else {
>> >> +                    plane->degamma.dirty = false;
>> >> +            }
>> >> +    }
>> >> +}
>> >> +
>> >> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi)
>> >> +{
>> >> +    struct dc_hw_plane *plane = &hw->plane[id];
>> >> +
>> >> +    if (plane) {
>> >> +            memcpy(&plane->roi, roi, sizeof(*roi) - sizeof(roi->dirty));
>> >> +            plane->roi.dirty = true;
>> >> +    }
>> >> +}
>> >> +
>> >> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
>> >> +                       struct dc_hw_colorkey *colorkey)
>> >> +{
>> >> +    struct dc_hw_plane *plane = &hw->plane[id];
>> >> +
>> >> +    if (plane) {
>> >> +            memcpy(&plane->colorkey, colorkey,
>> >> +                   sizeof(*colorkey) - sizeof(colorkey->dirty));
>> >> +            plane->colorkey.dirty = true;
>> >> +    }
>> >> +}
>> >> +
>> >> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos)
>> >> +{
>> >> +    memcpy(&hw->qos, qos, sizeof(*qos) - sizeof(qos->dirty));
>> >> +    hw->qos.dirty = true;
>> >> +}
>> >> +
>> >> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor)
>> >> +{
>> >> +    memcpy(&hw->cursor[id], cursor, sizeof(*cursor) - sizeof(cursor->dirty));
>> >> +    hw->cursor[id].dirty = true;
>> >> +}
>> >> +
>> >> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
>> >> +                    u16 r, u16 g, u16 b)
>> >> +{
>> >> +    if (index >= hw->info->gamma_size)
>> >> +            return;
>> >> +
>> >> +    hw->gamma[id].gamma[index][0] = r;
>> >> +    hw->gamma[id].gamma[index][1] = g;
>> >> +    hw->gamma[id].gamma[index][2] = b;
>> >> +    hw->gamma[id].dirty = true;
>> >> +}
>> >> +
>> >> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
>> >> +{
>> >> +    hw->gamma[id].enable = enable;
>> >> +    hw->gamma[id].dirty = true;
>> >> +}
>> >> +
>> >> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display)
>> >> +{
>> >> +    u8 id = display->id;
>> >> +
>> >> +    memcpy(&hw->display[id], display, sizeof(*display));
>> >> +
>> >> +    hw->func->display(hw, display);
>> >> +}
>> >> +
>> >> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable)
>> >> +{
>> >> +    if (enable)
>> >> +            hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
>> >> +    else
>> >> +            hi_write(hw, AQ_INTR_ENBL, 0);
>> >> +}
>> >> +
>> >> +u32 dc_hw_get_interrupt(struct dc_hw *hw)
>> >> +{
>> >> +    return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
>> >> +}
>> >> +
>> >> +bool dc_hw_check_underflow(struct dc_hw *hw)
>> >> +{
>> >> +    return dc_read(hw, DC_FRAMEBUFFER_CONFIG) & BIT(5);
>> >> +}
>> >> +
>> >> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable)
>> >> +{
>> >> +    u32 i, offset;
>> >> +    u8 id, layer_num = hw->info->layer_num;
>> >> +    u8 panel_num = hw->info->panel_num;
>> >> +
>> >> +    for (i = 0; i < layer_num; i++) {
>> >> +            id = hw->info->planes[i].id;
>> >> +            offset = get_addr_offset(id);
>> >> +            if (enable) {
>> >> +                    if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
>> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, BIT(12), 0);
>> >> +                    else
>> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, BIT(31), 0);
>> >> +            } else {
>> >> +                    if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
>> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, 0, BIT(12));
>> >> +                    else
>> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, 0, BIT(31));
>> >> +            }
>> >> +    }
>> >> +
>> >> +    for (i = 0; i < panel_num; i++) {
>> >> +            offset = i << 2;
>> >> +            if (enable)
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, BIT(0));
>> >> +            else
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, BIT(0), 0);
>> >> +    }
>> >> +}
>> >> +
>> >> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
>> >> +{
>> >> +    if (out <= OUT_DP)
>> >> +            hw->out[id] = out;
>> >> +}
>> >> +
>> >> +static void gamma_ex_commit(struct dc_hw *hw)
>> >> +{
>> >> +    u8 panel_num = hw->info->panel_num;
>> >> +    u16 i, j;
>> >> +    u32 value;
>> >> +
>> >> +    for (j = 0; j < panel_num; j++) {
>> >> +            if (hw->gamma[j].dirty) {
>> >> +                    if (hw->gamma[j].enable) {
>> >> +                            dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (j << 2), 0x00);
>> >> +                            for (i = 0; i < GAMMA_EX_SIZE; i++) {
>> >> +                                    value = hw->gamma[j].gamma[i][2] |
>> >> +                                            (hw->gamma[j].gamma[i][1] << 12);
>> >> +                                    dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (j << 2), value);
>> >> +                                    dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (j << 2),
>> >> +                                             hw->gamma[j].gamma[i][0]);
>> >> +                            }
>> >> +                            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
>> >> +                                         BIT(13), 0);
>> >> +                    } else {
>> >> +                            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
>> >> +                                         0, BIT(13));
>> >> +                    }
>> >> +                    hw->gamma[j].dirty = false;
>> >> +            }
>> >> +    }
>> >> +}
>> >> +
>> >> +static void plane_commit(struct dc_hw *hw)
>> >> +{
>> >> +    struct dc_hw_plane *plane;
>> >> +    const struct dc_hw_plane_reg *reg;
>> >> +    bool primary = false;
>> >> +    u8 id, layer_num = hw->info->layer_num;
>> >> +    u32 i, offset;
>> >> +
>> >> +    for (i = 0; i < layer_num; i++) {
>> >> +            plane = &hw->plane[i];
>> >> +            id = hw->info->planes[i].id;
>> >> +            offset = get_addr_offset(id);
>> >> +            if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
>> >> +                    reg = &dc_plane_reg[0];
>> >> +                    primary = true;
>> >> +            } else {
>> >> +                    reg = &dc_plane_reg[1];
>> >> +                    primary = false;
>> >> +            }
>> >
>> > Can you please move register defines to some internal hw_plane
>> > structure. These details are known at the time of creation of the plane.
>> > There is no need to determine them again and again.
>> >
>> >> +
>> >> +            if (plane->fb.dirty) {
>> >> +                    if (plane->fb.enable) {
>> >
>> > if (plane->fb.dirty && plane->fb.enable) will save you one level of
>> > indentation.
>> >
>> > However it might be better to use existing DRM flags instead of
>> > inventing your own flags.
>> >
>> >> +                            dc_write(hw, reg->y_address + offset,
>> >> +                                     plane->fb.y_address);
>> >> +                            dc_write(hw, reg->u_address + offset,
>> >> +                                     plane->fb.u_address);
>> >> +                            dc_write(hw, reg->v_address + offset,
>> >> +                                     plane->fb.v_address);
>> >> +                            dc_write(hw, reg->y_stride + offset,
>> >> +                                     plane->fb.y_stride);
>> >> +                            dc_write(hw, reg->u_stride + offset,
>> >> +                                     plane->fb.u_stride);
>> >> +                            dc_write(hw, reg->v_stride + offset,
>> >> +                                     plane->fb.v_stride);
>> >> +                            dc_write(hw, reg->size + offset,
>> >> +                                     plane->fb.width |
>> >> +                                     (plane->fb.height << 15));
>> >> +                            dc_write(hw, reg->water_mark + offset,
>> >> +                                     plane->fb.water_mark);
>> >> +
>> >> +                            if (plane->fb.clear_enable)
>> >> +                                    dc_write(hw, reg->clear_value + offset,
>> >> +                                             plane->fb.clear_value);
>> >> +                    }
>> >> +
>> >> +                    if (primary) {
>> >
>> > You have two kinds of planes. Primary and overlays. Could you please
>> > split this code into two separate functions and define two vtables, one
>> > for primary planes and one for overlays. There is no need to stick
>> > everything into a single funcion that handles everything.
>> >
>> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
>> >> +                                         (plane->fb.format << 26) |
>> >> +                                         (plane->fb.uv_swizzle << 25) |
>> >> +                                         (plane->fb.swizzle << 23) |
>> >> +                                         (plane->fb.tile_mode << 17) |
>> >> +                                         (plane->fb.yuv_color_space << 14) |
>> >> +                                         (plane->fb.rotation << 11) |
>> >> +                                         (plane->fb.clear_enable << 8),
>> >> +                                         (0x1F << 26) |
>> >> +                                         BIT(25) |
>> >> +                                         (0x03 << 23) |
>> >> +                                         (0x1F << 17) |
>> >> +                                         (0x07 << 14) |
>> >> +                                         (0x07 << 11) |
>> >> +                                         BIT(8));
>> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                         (plane->fb.dec_enable << 1) |
>> >> +                                         (plane->fb.enable << 13) |
>> >> +                                         (plane->fb.zpos << 16) |
>> >> +                                         (plane->fb.display_id << 19),
>> >> +                                         BIT(1) | BIT(13) | (0x07 << 16) | BIT(19));
>> >
>> > It looks like this code can enjoy defining names for all the magic
>> > values. Otherwise it is impossible to support it.
>> >
>> >> +                    } else {
>> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> >> +                                         (plane->fb.dec_enable << 27) |
>> >> +                                         (plane->fb.clear_enable << 25) |
>> >> +                                         (plane->fb.enable << 24) |
>> >> +                                         (plane->fb.format << 16) |
>> >> +                                         (plane->fb.uv_swizzle << 15) |
>> >> +                                         (plane->fb.swizzle << 13) |
>> >> +                                         (plane->fb.tile_mode << 8) |
>> >> +                                         (plane->fb.yuv_color_space << 5) |
>> >> +                                         (plane->fb.rotation << 2),
>> >> +                                         BIT(27) |
>> >> +                                         BIT(25) |
>> >> +                                         BIT(24) |
>> >> +                                         (0x1F << 16) |
>> >> +                                         BIT(15) |
>> >> +                                         (0x03 << 13) |
>> >> +                                         (0x1F << 8) |
>> >> +                                         (0x07 << 5) |
>> >> +                                         (0x07 << 2));
>> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
>> >> +                                         plane->fb.zpos | (plane->fb.display_id << 3),
>> >> +                                         0x07 | BIT(3));
>> >> +                    }
>> >> +                    plane->fb.dirty = false;
>> >> +            }
>> >> +
>> >> +            if (plane->scale.dirty) {
>> >> +                    if (plane->scale.enable) {
>> >> +                            dc_write(hw, reg->scale_factor_x + offset,
>> >> +                                     plane->scale.scale_factor_x);
>> >> +                            dc_write(hw, reg->scale_factor_y + offset,
>> >> +                                     plane->scale.scale_factor_y);
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG + offset,
>> >> +                                                 BIT(22), 0);
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_SCALE_CONFIG + offset,
>> >> +                                                 BIT(8), 0);
>> >> +                    } else {
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG + offset,
>> >> +                                                 0, BIT(22));
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_SCALE_CONFIG + offset,
>> >> +                                                 0, BIT(8));
>> >> +                    }
>> >> +                    plane->scale.dirty = false;
>> >> +            }
>> >> +
>> >> +            if (plane->pos.dirty) {
>> >> +                    dc_write(hw, reg->top_left + offset,
>> >> +                             plane->pos.start_x |
>> >> +                             (plane->pos.start_y << 15));
>> >> +                    dc_write(hw, reg->bottom_right + offset,
>> >> +                             plane->pos.end_x |
>> >> +                             (plane->pos.end_y << 15));
>> >> +                    plane->pos.dirty = false;
>> >> +            }
>> >> +
>> >> +            if (plane->blend.dirty) {
>> >> +                    dc_write(hw, reg->src_global_color + offset,
>> >> +                             plane->blend.alpha << 24);
>> >> +                    dc_write(hw, reg->dst_global_color + offset,
>> >> +                             plane->blend.alpha << 24);
>> >> +                    switch (plane->blend.blend_mode) {
>> >> +                    case BLEND_PREMULTI:
>> >> +                            dc_write(hw, reg->blend_config + offset, 0x3450);
>> >> +                            break;
>> >> +                    case BLEND_COVERAGE:
>> >> +                            dc_write(hw, reg->blend_config + offset, 0x3950);
>> >> +                            break;
>> >> +                    case BLEND_PIXEL_NONE:
>> >> +                            dc_write(hw, reg->blend_config + offset, 0x3548);
>> >> +                            break;
>> >> +                    default:
>> >> +                            break;
>> >> +                    }
>> >> +                    plane->blend.dirty = false;
>> >> +            }
>> >> +
>> >> +            if (plane->colorkey.dirty) {
>> >> +                    dc_write(hw, reg->color_key + offset, plane->colorkey.colorkey);
>> >> +                    dc_write(hw, reg->color_key_high + offset,
>> >> +                             plane->colorkey.colorkey_high);
>> >> +
>> >> +                    if (primary)
>> >> +                            dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
>> >> +                                         plane->colorkey.transparency << 9, 0x03 << 9);
>> >> +                    else
>> >> +                            dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> >> +                                         plane->colorkey.transparency, 0x03);
>> >> +
>> >> +                    plane->colorkey.dirty = false;
>> >> +            }
>> >> +
>> >> +            if (plane->roi.dirty) {
>> >> +                    if (plane->roi.enable) {
>> >> +                            dc_write(hw, reg->roi_origin + offset,
>> >> +                                     plane->roi.x | (plane->roi.y << 16));
>> >> +                            dc_write(hw, reg->roi_size + offset,
>> >> +                                     plane->roi.width | (plane->roi.height << 16));
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 BIT(0), 0);
>> >> +                            else
>> >> +                                    dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> >> +                                                 BIT(22), 0);
>> >> +                    } else {
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 0, BIT(0));
>> >> +                            else
>> >> +                                    dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
>> >> +                                                 0, BIT(22));
>> >> +                    }
>> >> +                    plane->roi.dirty = false;
>> >> +            }
>> >> +    }
>> >> +}
>> >> +
>> >> +static void plane_ex_commit(struct dc_hw *hw)
>> >> +{
>> >> +    struct dc_hw_plane *plane;
>> >> +    const struct dc_hw_plane_reg *reg;
>> >> +    bool primary = false;
>> >> +    u8 id, layer_num = hw->info->layer_num;
>> >> +    u32 i, offset;
>> >> +
>> >> +    for (i = 0; i < layer_num; i++) {
>> >> +            plane = &hw->plane[i];
>> >> +            id = hw->info->planes[i].id;
>> >> +            offset = get_addr_offset(id);
>> >> +            if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
>> >> +                    reg = &dc_plane_reg[0];
>> >> +                    primary = true;
>> >> +            } else {
>> >> +                    reg = &dc_plane_reg[1];
>> >> +                    primary = false;
>> >> +            }
>> >> +
>> >> +            if (plane->fb.dirty) {
>> >> +                    if (is_rgb(plane->fb.format)) {
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 BIT(6), BIT(8));
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_CONFIG + offset,
>> >> +                                                 BIT(29), BIT(30));
>> >> +                    } else {
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 BIT(8), BIT(6));
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_CONFIG + offset,
>> >> +                                                 BIT(30), BIT(29));
>> >> +                            switch (plane->fb.yuv_color_space) {
>> >> +                            case COLOR_SPACE_601:
>> >> +                                    load_yuv_to_rgb(hw, reg, offset, YUV601_2RGB);
>> >> +                                    break;
>> >> +                            case COLOR_SPACE_709:
>> >> +                                    load_yuv_to_rgb(hw, reg, offset, YUV709_2RGB);
>> >> +                                    break;
>> >> +                            case COLOR_SPACE_2020:
>> >> +                                    load_yuv_to_rgb(hw, reg, offset, YUV2020_2RGB);
>> >> +                                    break;
>> >> +                            default:
>> >> +                                    break;
>> >> +                            }
>> >> +                    }
>> >> +            }
>> >> +            if (plane->degamma.dirty) {
>> >> +                    switch (plane->degamma.mode) {
>> >> +                    case VS_DEGAMMA_DISABLE:
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 0, BIT(5));
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_CONFIG + offset,
>> >> +                                                 0, BIT(28));
>> >> +                            break;
>> >> +                    case VS_DEGAMMA_BT709:
>> >> +                            load_degamma_table(hw, reg, offset, DEGAMMA_709);
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 BIT(5), 0);
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_CONFIG + offset,
>> >> +                                                 BIT(28), 0);
>> >> +                            break;
>> >> +                    case VS_DEGAMMA_BT2020:
>> >> +                            load_degamma_table(hw, reg, offset, DEGAMMA_2020);
>> >> +                            if (primary)
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_FRAMEBUFFER_CONFIG_EX + offset,
>> >> +                                                 BIT(5), 0);
>> >> +                            else
>> >> +                                    dc_set_clear(hw,
>> >> +                                                 DC_OVERLAY_CONFIG + offset,
>> >> +                                                 BIT(28), 0);
>> >> +                            break;
>> >> +                    default:
>> >> +                            break;
>> >> +                    }
>> >> +                    plane->degamma.dirty = false;
>> >> +            }
>> >> +    }
>> >> +    plane_commit(hw);
>> >> +}
>> >> +
>> >> +static void setup_display(struct dc_hw *hw, struct dc_hw_display *display)
>> >> +{
>> >> +    u8 id = display->id;
>> >> +    u32 dpi_cfg, offset = id << 2;
>> >> +
>> >> +    if (hw->display[id].enable) {
>> >> +            switch (display->bus_format) {
>> >> +            case MEDIA_BUS_FMT_RGB565_1X16:
>> >> +                    dpi_cfg = 0;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB666_1X18:
>> >> +                    dpi_cfg = 3;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
>> >> +                    dpi_cfg = 4;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB888_1X24:
>> >> +                    dpi_cfg = 5;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB101010_1X30:
>> >> +                    dpi_cfg = 6;
>> >> +                    break;
>> >> +            default:
>> >> +                    dpi_cfg = 5;
>> >> +                    break;
>> >> +            }
>> >> +            dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
>> >> +
>> >> +            if (id == 0)
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
>> >> +            else
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
>> >> +
>> >> +            dc_write(hw, DC_DISPLAY_H + offset, hw->display[id].h_active |
>> >> +                     (hw->display[id].h_total << 16));
>> >> +            dc_write(hw, DC_DISPLAY_H_SYNC + offset,
>> >> +                     hw->display[id].h_sync_start |
>> >> +                     (hw->display[id].h_sync_end << 15) |
>> >> +                     (hw->display[id].h_sync_polarity ? 0 : BIT(31)) |
>> >> +                     BIT(30));
>> >> +            dc_write(hw, DC_DISPLAY_V + offset, hw->display[id].v_active |
>> >> +                            (hw->display[id].v_total << 16));
>> >> +            dc_write(hw, DC_DISPLAY_V_SYNC + offset,
>> >> +                     hw->display[id].v_sync_start |
>> >> +                     (hw->display[id].v_sync_end << 15) |
>> >> +                     (hw->display[id].v_sync_polarity ? 0 : BIT(31)) |
>> >> +                     BIT(30));
>> >> +
>> >> +            if (hw->info->pipe_sync)
>> >> +                    dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
>> >> +                                 0, BIT(3) | BIT(4));
>> >> +
>> >> +            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(12), 0);
>> >> +            if (id == 0)
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(0), BIT(3));
>> >> +            else
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(1), BIT(3));
>> >> +    } else {
>> >> +            dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(12));
>> >> +            if (id == 0)
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
>> >> +            else
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
>> >> +    }
>> >> +}
>> >> +
>> >> +static void setup_display_ex(struct dc_hw *hw, struct dc_hw_display *display)
>> >> +{
>> >> +    u8 id = display->id;
>> >> +    u32 dp_cfg, offset = id << 2;
>> >> +    bool is_yuv = false;
>> >> +
>> >> +    if (hw->display[id].enable && hw->out[id] == OUT_DP) {
>> >> +            switch (display->bus_format) {
>> >> +            case MEDIA_BUS_FMT_RGB565_1X16:
>> >> +                    dp_cfg = 0;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB666_1X18:
>> >> +                    dp_cfg = 1;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB888_1X24:
>> >> +                    dp_cfg = 2;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_RGB101010_1X30:
>> >> +                    dp_cfg = 3;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_UYVY8_1X16:
>> >> +                    dp_cfg = 2 << 4;
>> >> +                    is_yuv = true;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_YUV8_1X24:
>> >> +                    dp_cfg = 4 << 4;
>> >> +                    is_yuv = true;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_UYVY10_1X20:
>> >> +                    dp_cfg = 8 << 4;
>> >> +                    is_yuv = true;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_YUV10_1X30:
>> >> +                    dp_cfg = 10 << 4;
>> >> +                    is_yuv = true;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
>> >> +                    dp_cfg = 12 << 4;
>> >> +                    is_yuv = true;
>> >> +                    break;
>> >> +            case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
>> >> +                    dp_cfg = 13 << 4;
>> >> +                    is_yuv = true;
>> >> +                    break;
>> >> +            default:
>> >> +                    dp_cfg = 2;
>> >> +                    break;
>> >> +            }
>> >> +            if (is_yuv)
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(16), 0);
>> >> +            else
>> >> +                    dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(16));
>> >> +            dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | BIT(3));
>> >> +    }
>> >> +
>> >> +    if (hw->out[id] == OUT_DPI)
>> >> +            dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, BIT(3));
>> >> +
>> >> +    setup_display(hw, display);
>> >> +}
>> >> +
>> >> +static const struct dc_hw_funcs hw_func = {
>> >> +    .gamma = &gamma_ex_commit,
>> >> +    .plane = &plane_ex_commit,
>> >> +    .display = setup_display_ex,
>> >> +};
>> >> +
>> >> +void dc_hw_commit(struct dc_hw *hw)
>> >> +{
>> >> +    u32 i, offset = 0;
>> >> +    u8 plane_num = hw->info->plane_num;
>> >> +    u8 layer_num = hw->info->layer_num;
>> >> +    u8 cursor_num = plane_num - layer_num;
>> >> +
>> >> +    hw->func->gamma(hw);
>> >> +    hw->func->plane(hw);
>> >> +
>> >> +    for (i = 0; i < cursor_num; i++) {
>> >> +            if (hw->cursor[i].dirty) {
>> >> +                    offset = hw->cursor[i].display_id ? DC_CURSOR_OFFSET : 0;
>> >> +                    if (hw->cursor[i].enable) {
>> >> +                            dc_write(hw, DC_CURSOR_ADDRESS + offset,
>> >> +                                     hw->cursor[i].address);
>> >> +                            dc_write(hw, DC_CURSOR_LOCATION + offset, hw->cursor[i].x |
>> >> +                                     (hw->cursor[i].y << 16));
>> >> +                            dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
>> >> +                                         (hw->cursor[i].hot_x << 16) |
>> >> +                                         (hw->cursor[i].hot_y << 8) |
>> >> +                                         (hw->cursor[i].size << 5) |
>> >> +                                         BIT(3) | BIT(2) | 0x02,
>> >> +                                         (0xFF << 16) |
>> >> +                                         (0xFF << 8) |
>> >> +                                         (0x07 << 5) | 0x1F);
>> >> +                    } else {
>> >> +                            dc_set_clear(hw, DC_CURSOR_CONFIG + offset, BIT(3), 0x03);
>> >> +                    }
>> >> +                    hw->cursor[i].dirty = false;
>> >> +            }
>> >> +    }
>> >> +
>> >> +    if (hw->qos.dirty) {
>> >> +            dc_set_clear(hw, DC_QOS_CONFIG, (hw->qos.high_value << 4) |
>> >> +                                     hw->qos.low_value, 0xFF);
>> >> +            hw->qos.dirty = false;
>> >> +    }
>> >> +}
>> >> +
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
>> >> new file mode 100644
>> >> index 000000000..9a1d767ae
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
>> >> @@ -0,0 +1,492 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#ifndef __VS_DC_HW_H__
>> >> +#define __VS_DC_HW_H__
>> >> +
>> >> +#define AQ_INTR_ACKNOWLEDGE                         0x0010
>> >> +#define AQ_INTR_ENBL                                        0x0014
>> >
>> > Please take care to align all the defines.
>> >
>> >> +#define DC_HW_REVISION                                      0x0024
>> >> +#define DC_HW_CHIP_CID                                      0x0030
>> >> +
>> >> +#define DC_REG_BASE                                         0x0800
>> >> +#define DC_REG_RANGE                                        0x2000
>> >> +#define DC_SEC_REG_OFFSET                           0x100000
>> >> +
>> >> +#define DC_FRAMEBUFFER_CONFIG                       0x1518
>> >> +#define DC_FRAMEBUFFER_CONFIG_EX            0x1CC0
>> >> +#define DC_FRAMEBUFFER_SCALE_CONFIG         0x1520
>> >> +#define DC_FRAMEBUFFER_TOP_LEFT                     0x24D8
>> >> +#define DC_FRAMEBUFFER_BOTTOM_RIGHT         0x24E0
>> >> +#define DC_FRAMEBUFFER_ADDRESS                      0x1400
>> >> +#define DC_FRAMEBUFFER_U_ADDRESS            0x1530
>> >> +#define DC_FRAMEBUFFER_V_ADDRESS            0x1538
>> >> +#define DC_FRAMEBUFFER_STRIDE                       0x1408
>> >> +#define DC_FRAMEBUFFER_U_STRIDE                     0x1800
>> >> +#define DC_FRAMEBUFFER_V_STRIDE                     0x1808
>> >> +#define DC_FRAMEBUFFER_SIZE                         0x1810
>> >> +#define DC_FRAMEBUFFER_SCALE_FACTOR_X               0x1828
>> >> +#define DC_FRAMEBUFFER_SCALE_FACTOR_Y               0x1830
>> >> +#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX  0x1838
>> >> +#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA   0x1A00
>> >> +#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX  0x1A08
>> >> +#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA   0x1A10
>> >> +#define DC_FRAMEBUFFER_INIT_OFFSET                  0x1A20
>> >> +#define DC_FRAMEBUFFER_COLOR_KEY                    0x1508
>> >> +#define DC_FRAMEBUFFER_COLOR_KEY_HIGH               0x1510
>> >> +#define DC_FRAMEBUFFER_CLEAR_VALUE                  0x1A18
>> >> +#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX    0x1818
>> >> +#define DC_FRAMEBUFFER_COLOR_TABLE_DATA             0x1820
>> >> +#define DC_FRAMEBUFFER_BG_COLOR                             0x1528
>> >> +#define DC_FRAMEBUFFER_ROI_ORIGIN                   0x1CB0
>> >> +#define DC_FRAMEBUFFER_ROI_SIZE                             0x1CB8
>> >> +#define DC_FRAMEBUFFER_WATER_MARK                   0x1CE8
>> >> +#define DC_FRAMEBUFFER_DEGAMMA_INDEX                0x1D88
>> >> +#define DC_FRAMEBUFFER_DEGAMMA_DATA                 0x1D90
>> >> +#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA              0x1D98
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF0               0x1DA0
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF1               0x1DA8
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF2               0x1DB0
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF3               0x1DB8
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEF4               0x1E00
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD0              0x1E08
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD1              0x1E10
>> >> +#define DC_FRAMEBUFFER_YUVTORGB_COEFD2              0x1E18
>> >> +#define DC_FRAMEBUFFER_Y_CLAMP_BOUND                0x1E88
>> >> +#define DC_FRAMEBUFFER_UV_CLAMP_BOUND               0x1E90
>> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF0               0x1E20
>> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF1               0x1E28
>> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF2               0x1E30
>> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF3               0x1E38
>> >> +#define DC_FRAMEBUFFER_RGBTORGB_COEF4               0x1E40
>> >> +#define DC_FRAMEBUFFER_BLEND_CONFIG                 0x2510
>> >> +#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR             0x2500
>> >> +#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR             0x2508
>> >> +
>> >> +#define DC_OVERLAY_CONFIG                                   0x1540
>> >> +#define DC_OVERLAY_CONFIG_EX                                0x2540
>> >> +#define DC_OVERLAY_SCALE_CONFIG                             0x1C00
>> >> +#define DC_OVERLAY_BLEND_CONFIG                             0x1580
>> >> +#define DC_OVERLAY_TOP_LEFT                                 0x1640
>> >> +#define DC_OVERLAY_BOTTOM_RIGHT                             0x1680
>> >> +#define DC_OVERLAY_ADDRESS                                  0x15C0
>> >> +#define DC_OVERLAY_U_ADDRESS                                0x1840
>> >> +#define DC_OVERLAY_V_ADDRESS                                0x1880
>> >> +#define DC_OVERLAY_STRIDE                                   0x1600
>> >> +#define DC_OVERLAY_U_STRIDE                                 0x18C0
>> >> +#define DC_OVERLAY_V_STRIDE                                 0x1900
>> >> +#define DC_OVERLAY_SIZE                                             0x17C0
>> >> +#define DC_OVERLAY_SCALE_FACTOR_X                   0x1A40
>> >> +#define DC_OVERLAY_SCALE_FACTOR_Y                   0x1A80
>> >> +#define DC_OVERLAY_H_FILTER_COEF_INDEX              0x1AC0
>> >> +#define DC_OVERLAY_H_FILTER_COEF_DATA               0x1B00
>> >> +#define DC_OVERLAY_V_FILTER_COEF_INDEX              0x1B40
>> >> +#define DC_OVERLAY_V_FILTER_COEF_DATA               0x1B80
>> >> +#define DC_OVERLAY_INIT_OFFSET                              0x1BC0
>> >> +#define DC_OVERLAY_COLOR_KEY                                0x1740
>> >> +#define DC_OVERLAY_COLOR_KEY_HIGH                   0x1780
>> >> +#define DC_OVERLAY_CLEAR_VALUE                              0x1940
>> >> +#define DC_OVERLAY_COLOR_TABLE_INDEX                0x1980
>> >> +#define DC_OVERLAY_COLOR_TABLE_DATA                 0x19C0
>> >> +#define DC_OVERLAY_SRC_GLOBAL_COLOR                 0x16C0
>> >> +#define DC_OVERLAY_DST_GLOBAL_COLOR                 0x1700
>> >> +#define DC_OVERLAY_ROI_ORIGIN                               0x1D00
>> >> +#define DC_OVERLAY_ROI_SIZE                                 0x1D40
>> >> +#define DC_OVERLAY_WATER_MARK                               0x1DC0
>> >> +#define DC_OVERLAY_DEGAMMA_INDEX                    0x2200
>> >> +#define DC_OVERLAY_DEGAMMA_DATA                             0x2240
>> >> +#define DC_OVERLAY_DEGAMMA_EX_DATA                  0x2280
>> >> +#define DC_OVERLAY_YUVTORGB_COEF0                   0x1EC0
>> >> +#define DC_OVERLAY_YUVTORGB_COEF1                   0x1F00
>> >> +#define DC_OVERLAY_YUVTORGB_COEF2                   0x1F40
>> >> +#define DC_OVERLAY_YUVTORGB_COEF3                   0x1F80
>> >> +#define DC_OVERLAY_YUVTORGB_COEF4                   0x1FC0
>> >> +#define DC_OVERLAY_YUVTORGB_COEFD0                  0x2000
>> >> +#define DC_OVERLAY_YUVTORGB_COEFD1                  0x2040
>> >> +#define DC_OVERLAY_YUVTORGB_COEFD2                  0x2080
>> >> +#define DC_OVERLAY_Y_CLAMP_BOUND                    0x22C0
>> >> +#define DC_OVERLAY_UV_CLAMP_BOUND                   0x2300
>> >> +#define DC_OVERLAY_RGBTORGB_COEF0                   0x20C0
>> >> +#define DC_OVERLAY_RGBTORGB_COEF1                   0x2100
>> >> +#define DC_OVERLAY_RGBTORGB_COEF2                   0x2140
>> >> +#define DC_OVERLAY_RGBTORGB_COEF3                   0x2180
>> >> +#define DC_OVERLAY_RGBTORGB_COEF4                   0x21C0
>> >> +
>> >> +#define DC_CURSOR_CONFIG                                    0x1468
>> >> +#define DC_CURSOR_ADDRESS                                   0x146C
>> >> +#define DC_CURSOR_LOCATION                                  0x1470
>> >> +#define DC_CURSOR_BACKGROUND                                0x1474
>> >> +#define DC_CURSOR_FOREGROUND                                0x1478
>> >> +#define DC_CURSOR_CLK_GATING                                0x1484
>> >> +#define DC_CURSOR_CONFIG_EX                                 0x24E8
>> >> +#define DC_CURSOR_OFFSET                                    0x1080
>> >> +
>> >> +#define DC_DISPLAY_DITHER_CONFIG            0x1410
>> >> +#define DC_DISPLAY_PANEL_CONFIG                     0x1418
>> >> +#define DC_DISPLAY_PANEL_CONFIG_EX          0x2518
>> >> +#define DC_DISPLAY_DITHER_TABLE_LOW         0x1420
>> >> +#define DC_DISPLAY_DITHER_TABLE_HIGH        0x1428
>> >> +#define DC_DISPLAY_H                                        0x1430
>> >> +#define DC_DISPLAY_H_SYNC                           0x1438
>> >> +#define DC_DISPLAY_V                                        0x1440
>> >> +#define DC_DISPLAY_V_SYNC                           0x1448
>> >> +#define DC_DISPLAY_CURRENT_LOCATION         0x1450
>> >> +#define DC_DISPLAY_GAMMA_INDEX                      0x1458
>> >> +#define DC_DISPLAY_GAMMA_DATA                       0x1460
>> >> +#define DC_DISPLAY_INT                                      0x147C
>> >> +#define DC_DISPLAY_INT_ENABLE                       0x1480
>> >> +#define DC_DISPLAY_DBI_CONFIG                       0x1488
>> >> +#define DC_DISPLAY_GENERAL_CONFIG           0x14B0
>> >> +#define DC_DISPLAY_DPI_CONFIG                       0x14B8
>> >> +#define DC_DISPLAY_PANEL_START                      0x1CCC
>> >> +#define DC_DISPLAY_DEBUG_COUNTER_SELECT             0x14D0
>> >> +#define DC_DISPLAY_DEBUG_COUNTER_VALUE              0x14D8
>> >> +#define DC_DISPLAY_DP_CONFIG                                0x1CD0
>> >> +#define DC_DISPLAY_GAMMA_EX_INDEX                   0x1CF0
>> >> +#define DC_DISPLAY_GAMMA_EX_DATA                    0x1CF8
>> >> +#define DC_DISPLAY_GAMMA_EX_ONE_DATA                0x1D80
>> >> +#define DC_DISPLAY_RGBTOYUV_COEF0                   0x1E48
>> >> +#define DC_DISPLAY_RGBTOYUV_COEF1                   0x1E50
>> >> +#define DC_DISPLAY_RGBTOYUV_COEF2                   0x1E58
>> >> +#define DC_DISPLAY_RGBTOYUV_COEF3                   0x1E60
>> >> +#define DC_DISPLAY_RGBTOYUV_COEF4                   0x1E68
>> >> +#define DC_DISPLAY_RGBTOYUV_COEFD0                  0x1E70
>> >> +#define DC_DISPLAY_RGBTOYUV_COEFD1                  0x1E78
>> >> +#define DC_DISPLAY_RGBTOYUV_COEFD2                  0x1E80
>> >> +
>> >> +#define DC_CLK_GATTING                                      0x1A28
>> >> +#define DC_QOS_CONFIG                                       0x1A38
>> >> +
>> >> +#define DC_TRANSPARENCY_OPAQUE                      0x00
>> >> +#define DC_TRANSPARENCY_KEY                         0x02
>> >> +#define DC_DISPLAY_DITHERTABLE_LOW          0x7B48F3C0
>> >> +#define DC_DISPLAY_DITHERTABLE_HIGH         0x596AD1E2
>> >> +
>> >> +#define GAMMA_SIZE                                          256
>> >> +#define GAMMA_EX_SIZE                                       300
>> >> +#define DEGAMMA_SIZE                                        260
>> >> +
>> >> +#define RGB_TO_RGB_TABLE_SIZE                       9
>> >> +#define YUV_TO_RGB_TABLE_SIZE                       16
>> >> +#define RGB_TO_YUV_TABLE_SIZE                       12
>> >> +
>> >> +#define DC_LAYER_NUM        6
>> >> +#define DC_DISPLAY_NUM      2
>> >> +#define DC_CURSOR_NUM       2
>> >> +
>> >> +#define DC_TILE_MODE4X4     0x15
>> >> +
>> >> +enum dc_chip_rev {
>> >> +    DC_REV_0,/* For HW_REV_5720,HW_REV_5721_311 */
>> >> +    DC_REV_1,/* For HW_REV_5721_30B */
>> >> +    DC_REV_2,/* For HW_REV_5721_310 */
>> >> +};
>> >> +
>> >> +enum dc_hw_plane_id {
>> >> +    PRIMARY_PLANE_0,
>> >> +    OVERLAY_PLANE_0,
>> >> +    OVERLAY_PLANE_1,
>> >> +    PRIMARY_PLANE_1,
>> >> +    OVERLAY_PLANE_2,
>> >> +    OVERLAY_PLANE_3,
>> >> +    CURSOR_PLANE_0,
>> >> +    CURSOR_PLANE_1,
>> >> +    PLANE_NUM
>> >> +};
>> >> +
>> >> +enum dc_hw_color_format {
>> >> +    FORMAT_X4R4G4B4,//0
>> >
>> > Space after the comma will make it more readable. Or just define the
>> > values explicitly, it will also be more readable.
>> >
>> >> +    FORMAT_A4R4G4B4,//1
>> >> +    FORMAT_X1R5G5B5,//2
>> >> +    FORMAT_A1R5G5B5,//3
>> >> +    FORMAT_R5G6B5,//4
>> >> +    FORMAT_X8R8G8B8,//5
>> >> +    FORMAT_A8R8G8B8,//6
>> >> +    FORMAT_YUY2,//7
>> >> +    FORMAT_UYVY,//8
>> >> +    FORMAT_INDEX8,//9
>> >> +    FORMAT_MONOCHROME,//10
>> >> +    FORMAT_YV12 = 0xf,
>> >> +    FORMAT_A8,//16
>> >> +    FORMAT_NV12,//17
>> >> +    FORMAT_NV16,//18
>> >> +    FORMAT_RG16,//19
>> >> +    FORMAT_R8,//20
>> >> +    FORMAT_NV12_10BIT,//21
>> >> +    FORMAT_A2R10G10B10,//22
>> >> +    FORMAT_NV16_10BIT,//23
>> >> +    FORMAT_INDEX1,//24
>> >> +    FORMAT_INDEX2,//25
>> >> +    FORMAT_INDEX4,//26
>> >> +    FORMAT_P010,//27
>> >> +    FORMAT_YUV444,//28
>> >> +    FORMAT_YUV444_10BIT,//29
>> >> +};
>> >> +
>> >> +enum dc_hw_yuv_color_space {
>> >> +    COLOR_SPACE_601 = 0,
>> >> +    COLOR_SPACE_709 = 1,
>> >> +    COLOR_SPACE_2020 = 3,
>> >> +};
>> >> +
>> >> +enum dc_hw_rotation {
>> >> +    ROT_0 = 0,
>> >> +    ROT_90 = 4,
>> >> +    ROT_180 = 5,
>> >> +    ROT_270 = 6,
>> >> +    FLIP_X = 1,
>> >> +    FLIP_Y = 2,
>> >> +    FLIP_XY = 3,
>> >> +};
>> >> +
>> >> +enum dc_hw_swizzle {
>> >> +    SWIZZLE_ARGB = 0,
>> >> +    SWIZZLE_RGBA,
>> >> +    SWIZZLE_ABGR,
>> >> +    SWIZZLE_BGRA,
>> >> +};
>> >> +
>> >> +enum dc_hw_out {
>> >> +    OUT_DPI,
>> >> +    OUT_DP,
>> >> +};
>> >> +
>> >> +enum dc_hw_cursor_size {
>> >> +    CURSOR_SIZE_32X32 = 0,
>> >> +    CURSOR_SIZE_64X64,
>> >> +};
>> >> +
>> >> +enum dc_hw_blend_mode {
>> >> +    /* out.rgb = plane_alpha * fg.rgb +
>> >> +     *              (1 - (plane_alpha * fg.alpha)) * bg.rgb
>> >> +     */
>> >> +    BLEND_PREMULTI,
>> >> +    /* out.rgb = plane_alpha * fg.alpha * fg.rgb +
>> >> +     *              (1 - (plane_alpha * fg.alpha)) * bg.rgb
>> >> +     */
>> >> +    BLEND_COVERAGE,
>> >> +    /* out.rgb = plane_alpha * fg.rgb +
>> >> +     *              (1 - plane_alpha) * bg.rgb
>> >> +     */
>> >> +    BLEND_PIXEL_NONE,
>> >
>> > Can you use defines from <drm/drm_blend.h>?
>> >
>> >> +};
>> >> +
>> >> +struct dc_hw_plane_reg {
>> >> +    u32 y_address;
>> >> +    u32 u_address;
>> >> +    u32 v_address;
>> >> +    u32 y_stride;
>> >> +    u32 u_stride;
>> >> +    u32 v_stride;
>> >> +    u32 size;
>> >> +    u32 top_left;
>> >> +    u32 bottom_right;
>> >> +    u32 scale_factor_x;
>> >> +    u32 scale_factor_y;
>> >> +    u32 h_filter_coef_index;
>> >> +    u32 h_filter_coef_data;
>> >> +    u32 v_filter_coef_index;
>> >> +    u32 v_filter_coef_data;
>> >> +    u32 init_offset;
>> >> +    u32 color_key;
>> >> +    u32 color_key_high;
>> >> +    u32 clear_value;
>> >> +    u32 color_table_index;
>> >> +    u32 color_table_data;
>> >> +    u32 scale_config;
>> >> +    u32 water_mark;
>> >> +    u32 degamma_index;
>> >> +    u32 degamma_data;
>> >> +    u32 degamma_ex_data;
>> >> +    u32 src_global_color;
>> >> +    u32 dst_global_color;
>> >> +    u32 blend_config;
>> >> +    u32 roi_origin;
>> >> +    u32 roi_size;
>> >> +    u32 yuv_to_rgb_coef0;
>> >> +    u32 yuv_to_rgb_coef1;
>> >> +    u32 yuv_to_rgb_coef2;
>> >> +    u32 yuv_to_rgb_coef3;
>> >> +    u32 yuv_to_rgb_coef4;
>> >> +    u32 yuv_to_rgb_coefd0;
>> >> +    u32 yuv_to_rgb_coefd1;
>> >> +    u32 yuv_to_rgb_coefd2;
>> >> +    u32 y_clamp_bound;
>> >> +    u32 uv_clamp_bound;
>> >> +    u32 rgb_to_rgb_coef0;
>> >> +    u32 rgb_to_rgb_coef1;
>> >> +    u32 rgb_to_rgb_coef2;
>> >> +    u32 rgb_to_rgb_coef3;
>> >> +    u32 rgb_to_rgb_coef4;
>> >> +};
>> >> +
>> >> +struct dc_hw_fb {
>> >> +    u32 y_address;
>> >> +    u32 u_address;
>> >> +    u32 v_address;
>> >> +    u32 clear_value;
>> >> +    u32 water_mark;
>> >> +    u16 y_stride;
>> >> +    u16 u_stride;
>> >> +    u16 v_stride;
>> >> +    u16 width;
>> >> +    u16 height;
>> >> +    u8      format;
>> >> +    u8      tile_mode;
>> >> +    u8      rotation;
>> >> +    u8      yuv_color_space;
>> >> +    u8      swizzle;
>> >> +    u8      uv_swizzle;
>> >> +    u8      zpos;
>> >> +    u8      display_id;
>> >> +    bool    clear_enable;
>> >> +    bool    dec_enable;
>> >> +    bool    enable;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_scale {
>> >> +    u32 scale_factor_x;
>> >> +    u32 scale_factor_y;
>> >> +    bool    enable;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_position {
>> >> +    u16 start_x;
>> >> +    u16 start_y;
>> >> +    u16 end_x;
>> >> +    u16 end_y;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_blend {
>> >> +    u8      alpha;
>> >> +    u8      blend_mode;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_colorkey {
>> >> +    u32 colorkey;
>> >> +    u32 colorkey_high;
>> >> +    u8      transparency;
>> >> +    bool dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_roi {
>> >> +    u16 x;
>> >> +    u16 y;
>> >> +    u16 width;
>> >> +    u16 height;
>> >> +    bool enable;
>> >> +    bool dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_cursor {
>> >> +    u32 address;
>> >> +    u16 x;
>> >> +    u16 y;
>> >> +    u16 hot_x;
>> >> +    u16 hot_y;
>> >> +    u8      size;
>> >> +    u8      display_id;
>> >> +    bool    enable;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_display {
>> >> +    u32 bus_format;
>> >> +    u16 h_active;
>> >> +    u16 h_total;
>> >> +    u16 h_sync_start;
>> >> +    u16 h_sync_end;
>> >> +    u16 v_active;
>> >> +    u16 v_total;
>> >> +    u16 v_sync_start;
>> >> +    u16 v_sync_end;
>> >> +    u8      id;
>> >> +    bool    h_sync_polarity;
>> >> +    bool    v_sync_polarity;
>> >> +    bool    enable;
>> >> +};
>> >> +
>> >> +struct dc_hw_gamma {
>> >> +    u16 gamma[GAMMA_EX_SIZE][3];
>> >> +    bool    enable;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_degamma {
>> >> +    u16 degamma[DEGAMMA_SIZE][3];
>> >> +    u32 mode;
>> >> +    bool    dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_plane {
>> >> +    struct dc_hw_fb                 fb;
>> >> +    struct dc_hw_position   pos;
>> >> +    struct dc_hw_scale              scale;
>> >> +    struct dc_hw_blend              blend;
>> >> +    struct dc_hw_roi                roi;
>> >> +    struct dc_hw_colorkey   colorkey;
>> >> +    struct dc_hw_degamma    degamma;
>> >> +};
>> >> +
>> >> +struct dc_hw_qos {
>> >> +    u8        low_value;
>> >> +    u8        high_value;
>> >> +    bool  dirty;
>> >> +};
>> >> +
>> >> +struct dc_hw_read {
>> >> +    u32                     reg;
>> >> +    u32                     value;
>> >> +};
>> >> +
>> >> +struct dc_hw;
>> >> +struct dc_hw_funcs {
>> >> +    void (*gamma)(struct dc_hw *hw);
>> >> +    void (*plane)(struct dc_hw *hw);
>> >> +    void (*display)(struct dc_hw *hw, struct dc_hw_display *display);
>> >> +};
>> >> +
>> >> +struct dc_hw {
>> >> +    enum dc_chip_rev rev;
>> >> +    enum dc_hw_out          out[DC_DISPLAY_NUM];
>> >> +    void                    *hi_base;
>> >> +    void                    *reg_base;
>> >> +
>> >> +    struct dc_hw_display display[DC_DISPLAY_NUM];
>> >> +    struct dc_hw_gamma       gamma[DC_DISPLAY_NUM];
>> >> +    struct dc_hw_plane       plane[DC_LAYER_NUM];
>> >> +    struct dc_hw_cursor  cursor[DC_CURSOR_NUM];
>> >> +    struct dc_hw_qos         qos;
>> >> +    struct dc_hw_funcs       *func;
>> >> +    struct vs_dc_info        *info;
>> >> +};
>> >> +
>> >> +int dc_hw_init(struct dc_hw *hw);
>> >> +void dc_hw_deinit(struct dc_hw *hw);
>> >> +void dc_hw_update_plane(struct dc_hw *hw, u8 id,
>> >> +                    struct dc_hw_fb *fb, struct dc_hw_scale *scale,
>> >> +                    struct dc_hw_position *pos, struct dc_hw_blend *blend);
>> >> +void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode);
>> >> +void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi);
>> >> +void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
>> >> +                       struct dc_hw_colorkey *colorkey);
>> >> +void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos);
>> >> +void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor);
>> >> +void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
>> >> +                    u16 r, u16 g, u16 b);
>> >> +void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
>> >> +void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display);
>> >> +void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable);
>> >> +u32 dc_hw_get_interrupt(struct dc_hw *hw);
>> >> +bool dc_hw_check_underflow(struct dc_hw *hw);
>> >> +void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable);
>> >> +void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
>> >> +void dc_hw_commit(struct dc_hw *hw);
>> >> +
>> >> +#endif /* __VS_DC_HW_H__ */
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
>> >> index da7698c3d..3cd533cfa 100644
>> >> --- a/drivers/gpu/drm/verisilicon/vs_drv.c
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_drv.c
>> >> @@ -21,6 +21,7 @@
>> >>
>> >>   #include "vs_drv.h"
>> >>   #include "vs_modeset.h"
>> >> +#include "vs_dc.h"
>> >>
>> >>   #define DRV_NAME   "verisilicon"
>> >>   #define DRV_DESC   "Verisilicon DRM driver"
>> >> @@ -123,6 +124,7 @@ static const struct component_master_ops vs_drm_ops = {
>> >>   };
>> >>
>> >>   static struct platform_driver *drm_sub_drivers[] = {
>> >> +    &dc_platform_driver,
>> >>
>> >>   };
>> >>
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
>> >> new file mode 100644
>> >> index 000000000..9bd066015
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_plane.c
>> >> @@ -0,0 +1,526 @@
>> >> +// SPDX-License-Identifier: GPL-2.0
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#include <drm/drm_atomic.h>
>> >> +#include <drm/drm_atomic_helper.h>
>> >> +#include <drm/drm_blend.h>
>> >> +#include <drm/drm_gem_dma_helper.h>
>> >> +#include <drm/drm_fb_dma_helper.h>
>> >> +#include <drm/drm_framebuffer.h>
>> >> +#include <drm/drm_plane.h>
>> >> +#include <drm/drm_plane_helper.h>
>> >> +
>> >> +#include <drm/vs_drm.h>
>> >> +
>> >> +#include "vs_plane.h"
>> >> +#include "vs_drv.h"
>> >> +#include "vs_dc.h"
>> >> +
>> >> +static void vs_plane_reset(struct drm_plane *plane)
>> >> +{
>> >> +    struct vs_plane_state *state;
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +
>> >> +    if (plane->state) {
>> >> +            __drm_atomic_helper_plane_destroy_state(plane->state);
>> >> +
>> >> +            state = to_vs_plane_state(plane->state);
>> >> +            kfree(state);
>> >> +            plane->state = NULL;
>> >> +    }
>> >> +
>> >
>> > Use vs_plane_destroy_state directly. This way you won't miss a refcount
>> > on blobs.
>> >
>> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> >> +    if (!state)
>> >> +            return;
>> >> +
>> >> +    state->degamma = VS_DEGAMMA_DISABLE;
>> >> +    state->degamma_changed = false;
>> >> +    state->base.zpos = vs_plane->id;
>> >> +    memset(&state->status, 0, sizeof(state->status));
>> >> +
>> >> +    __drm_atomic_helper_plane_reset(plane, &state->base);
>> >> +}
>> >> +
>> >> +static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
>> >> +                                 struct vs_plane_state *ori_state)
>> >> +{
>> >> +    state->watermark = ori_state->watermark;
>> >> +    state->color_mgmt = ori_state->color_mgmt;
>> >> +    state->roi = ori_state->roi;
>> >> +
>> >> +    if (state->watermark)
>> >> +            drm_property_blob_get(state->watermark);
>> >> +    if (state->color_mgmt)
>> >> +            drm_property_blob_get(state->color_mgmt);
>> >> +    if (state->roi)
>> >> +            drm_property_blob_get(state->roi);
>> >> +}
>> >> +
>> >> +static int
>> >> +_vs_plane_set_property_blob_from_id(struct drm_device *dev,
>> >> +                                struct drm_property_blob **blob,
>> >> +                                u64 blob_id,
>> >> +                                size_t expected_size)
>> >> +{
>> >> +    struct drm_property_blob *new_blob = NULL;
>> >> +
>> >> +    if (blob_id) {
>> >> +            new_blob = drm_property_lookup_blob(dev, blob_id);
>> >> +            if (!new_blob)
>> >> +                    return -EINVAL;
>> >> +
>> >> +            if (new_blob->length != expected_size) {
>> >> +                    drm_property_blob_put(new_blob);
>> >> +                    return -EINVAL;
>> >> +            }
>> >> +    }
>> >> +
>> >> +    drm_property_replace_blob(blob, new_blob);
>> >> +    drm_property_blob_put(new_blob);
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static struct drm_plane_state *
>> >> +vs_plane_atomic_duplicate_state(struct drm_plane *plane)
>> >> +{
>> >> +    struct vs_plane_state *ori_state;
>> >> +    struct vs_plane_state *state;
>> >> +
>> >> +    if (WARN_ON(!plane->state))
>> >> +            return NULL;
>> >> +
>> >> +    ori_state = to_vs_plane_state(plane->state);
>> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> >> +    if (!state)
>> >> +            return NULL;
>> >> +
>> >> +    __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
>> >> +
>> >> +    state->degamma = ori_state->degamma;
>> >> +    state->degamma_changed = ori_state->degamma_changed;
>> >> +
>> >> +    _vs_plane_duplicate_blob(state, ori_state);
>> >> +    memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
>> >> +
>> >> +    return &state->base;
>> >> +}
>> >> +
>> >> +static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
>> >> +                                      struct drm_plane_state *state)
>> >> +{
>> >> +    struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
>> >> +
>> >> +    __drm_atomic_helper_plane_destroy_state(state);
>> >> +
>> >> +    drm_property_blob_put(vs_plane_state->watermark);
>> >> +    drm_property_blob_put(vs_plane_state->color_mgmt);
>> >> +    drm_property_blob_put(vs_plane_state->roi);
>> >> +    kfree(vs_plane_state);
>> >> +}
>> >> +
>> >> +static int vs_plane_atomic_set_property(struct drm_plane *plane,
>> >> +                                    struct drm_plane_state *state,
>> >> +                                    struct drm_property *property,
>> >> +                                    uint64_t val)
>> >> +{
>> >> +    struct drm_device *dev = plane->dev;
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +    struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
>> >> +    int ret = 0;
>> >> +
>> >> +    if (property == vs_plane->degamma_mode) {
>> >> +            if (vs_plane_state->degamma != val) {
>> >> +                    vs_plane_state->degamma = val;
>> >> +                    vs_plane_state->degamma_changed = true;
>> >> +            } else {
>> >> +                    vs_plane_state->degamma_changed = false;
>> >> +            }
>> >> +    } else if (property == vs_plane->watermark_prop) {
>> >> +            ret = _vs_plane_set_property_blob_from_id(dev,
>> >> +                                                      &vs_plane_state->watermark,
>> >> +                                                      val,
>> >> +                                                      sizeof(struct drm_vs_watermark));
>> >> +            return ret;
>> >> +    } else if (property == vs_plane->color_mgmt_prop) {
>> >> +            ret = _vs_plane_set_property_blob_from_id(dev,
>> >> +                                                      &vs_plane_state->color_mgmt,
>> >> +                                                      val,
>> >> +                                                      sizeof(struct drm_vs_color_mgmt));
>> >> +            return ret;
>> >> +    } else if (property == vs_plane->roi_prop) {
>> >> +            ret = _vs_plane_set_property_blob_from_id(dev,
>> >> +                                                      &vs_plane_state->roi,
>> >> +                                                      val,
>> >> +                                                      sizeof(struct drm_vs_roi));
>> >> +            return ret;
>> >> +    } else {
>> >> +            return -EINVAL;
>> >> +    }
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static int vs_plane_atomic_get_property(struct drm_plane *plane,
>> >> +                                    const struct drm_plane_state *state,
>> >> +                                    struct drm_property *property,
>> >> +                                    uint64_t *val)
>> >> +{
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +    const struct vs_plane_state *vs_plane_state =
>> >> +            container_of(state, const struct vs_plane_state, base);
>> >> +
>> >> +    if (property == vs_plane->degamma_mode)
>> >> +            *val = vs_plane_state->degamma;
>> >> +    else if (property == vs_plane->watermark_prop)
>> >> +            *val = (vs_plane_state->watermark) ?
>> >> +                                    vs_plane_state->watermark->base.id : 0;
>> >> +    else if (property == vs_plane->color_mgmt_prop)
>> >> +            *val = (vs_plane_state->color_mgmt) ?
>> >> +                                    vs_plane_state->color_mgmt->base.id : 0;
>> >
>> > degamma and color management should use standard properties.

hello Dmitry:
There is a question that troubles me

drm_plane include such standard properties.
{
	struct drm_property *alpha_property;
	struct drm_property *zpos_property;
	struct drm_property *rotation_property;
	struct drm_property *blend_mode_property;
	struct drm_property *color_encoding_property;
	struct drm_property *color_range_property;
	struct drm_property *scaling_filter_property;
}

it doesn't include degamma and color management properties

>> >
>> >> +    else if (property == vs_plane->roi_prop)
>> >> +            *val = (vs_plane_state->roi) ?
>> >> +                                    vs_plane_state->roi->base.id : 0;
>> >> +    else
>> >> +            return -EINVAL;
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static bool vs_format_mod_supported(struct drm_plane *plane,
>> >> +                                u32 format,
>> >> +                                u64 modifier)
>> >> +{
>> >> +    int i;
>> >> +
>> >> +    /* We always have to allow these modifiers:
>> >> +     * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
>> >> +     * 2. Not passing any modifiers is the same as explicitly passing INVALID.
>> >> +     */
>> >> +    if (modifier == DRM_FORMAT_MOD_LINEAR)
>> >> +            return true;
>> >> +
>> >> +    /* Check that the modifier is on the list of the plane's supported modifiers. */
>> >> +    for (i = 0; i < plane->modifier_count; i++) {
>> >> +            if (modifier == plane->modifiers[i])
>> >> +                    break;
>> >> +    }
>> >> +
>> >> +    if (i == plane->modifier_count)
>> >> +            return false;
>> >> +
>> >> +    return true;
>> >> +}
>> >> +
>> >> +const struct drm_plane_funcs vs_plane_funcs = {
>> >> +    .update_plane           = drm_atomic_helper_update_plane,
>> >> +    .disable_plane          = drm_atomic_helper_disable_plane,
>> >> +    .reset                  = vs_plane_reset,
>> >> +    .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
>> >> +    .atomic_destroy_state   = vs_plane_atomic_destroy_state,
>> >> +    .atomic_set_property    = vs_plane_atomic_set_property,
>> >> +    .atomic_get_property    = vs_plane_atomic_get_property,
>> >> +    .format_mod_supported   = vs_format_mod_supported,
>> >> +};
>> >> +
>> >> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
>> >> +{
>> >> +    const struct drm_format_info *info;
>> >> +
>> >> +    if (!fb)
>> >> +            return 0;
>> >> +
>> >> +    info = drm_format_info(fb->format->format);
>> >> +    if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
>> >> +            return 0;
>> >> +
>> >> +    return info->num_planes;
>> >> +}
>> >> +
>> >> +static int vs_plane_atomic_check(struct drm_plane *plane,
>> >> +                             struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> >> +                                                                             plane);
>> >> +    unsigned char i, num_planes;
>> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
>> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
>> >> +
>> >> +    if (!crtc || !fb)
>> >> +            return 0;
>> >> +
>> >> +    num_planes = vs_get_plane_number(fb);
>> >> +
>> >> +    for (i = 0; i < num_planes; i++) {
>> >> +            dma_addr_t dma_addr;
>> >> +
>> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
>> >> +            plane_state->dma_addr[i] = dma_addr;
>> >> +    }
>> >> +
>> >> +    return vs_dc_check_plane(dc, plane, state);
>> >> +}
>> >> +
>> >> +static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
>> >> +                                    struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> >> +                                                                      plane);
>> >> +    unsigned char i, num_planes;
>> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
>> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
>> >> +
>> >> +    if (!crtc || !fb)
>> >> +            return 0;
>> >> +
>> >> +    num_planes = vs_get_plane_number(fb);
>> >> +
>> >> +    for (i = 0; i < num_planes; i++) {
>> >> +            dma_addr_t dma_addr;
>> >> +
>> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
>> >> +            plane_state->dma_addr[i] = dma_addr;
>> >> +    }
>> >> +
>> >> +    return vs_dc_check_cursor_plane(dc, plane, state);
>> >> +}
>> >> +
>> >> +static void vs_plane_atomic_update(struct drm_plane *plane,
>> >> +                               struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> >> +                                                                      plane);
>> >
>> > New line after the equal sign will be better.
>> >
>> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> >> +                                                                      plane);
>> >> +
>> >> +    unsigned char i, num_planes;
>> >> +    struct drm_framebuffer *fb;
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    if (!new_state->fb || !new_state->crtc)
>> >> +            return;
>> >
>> > if (!new_state->visible) ?

no matter what value it is ? the driver will handle it
in func 

static void update_fb(struct vs_plane *plane, u8 display_id,
		      struct dc_hw_fb *fb, struct drm_plane_state *state)
{
	struct vs_plane_state *plane_state = to_vs_plane_state(state);
	struct drm_framebuffer *drm_fb = state->fb;
	struct drm_rect *src = &state->src;

.......
	fb->enable = state->visible;
.......
}

so no need add "if (!new_state->visible)" i think

>> >
>> >> +
>> >> +    fb = new_state->fb;
>> >> +
>> >> +    drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
>> >> +
>> >> +    num_planes = vs_get_plane_number(fb);
>> >> +
>> >> +    for (i = 0; i < num_planes; i++) {
>> >> +            dma_addr_t dma_addr;
>> >> +
>> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
>> >> +            plane_state->dma_addr[i] = dma_addr;
>> >> +    }
>> >> +
>> >> +    plane_state->status.src = drm_plane_state_src(new_state);
>> >> +    plane_state->status.dest = drm_plane_state_dest(new_state);
>> >> +
>> >> +    vs_dc_update_plane(dc, vs_plane, plane, state);
>> >> +}
>> >> +
>> >> +static void vs_cursor_plane_atomic_update(struct drm_plane *plane,
>> >> +                                      struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> >> +                                                                       plane);
>> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> >> +                                                                       plane);
>> >> +    unsigned char i, num_planes;
>> >> +    struct drm_framebuffer *fb;
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
>> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    if (!new_state->fb || !new_state->crtc)
>> >
>> > and here.
>> >
>> >> +            return;
>> >> +
>> >> +    fb = new_state->fb;
>> >> +    drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
>> >> +
>> >> +    num_planes = vs_get_plane_number(fb);
>> >> +
>> >> +    for (i = 0; i < num_planes; i++) {
>> >> +            dma_addr_t dma_addr;
>> >> +
>> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
>> >> +            plane_state->dma_addr[i] = dma_addr;
>> >> +    }
>> >> +
>> >> +    plane_state->status.src = drm_plane_state_src(new_state);
>> >> +    plane_state->status.dest = drm_plane_state_dest(new_state);
>> >> +
>> >> +    vs_dc_update_cursor_plane(dc, vs_plane, plane, state);
>> >> +}
>> >> +
>> >> +static void vs_plane_atomic_disable(struct drm_plane *plane,
>> >> +                                struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> >> +                                                                       plane);
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    vs_dc_disable_plane(dc, vs_plane, old_state);
>> >> +}
>> >> +
>> >> +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane,
>> >> +                                       struct drm_atomic_state *state)
>> >> +{
>> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
>> >> +                                                                       plane);
>> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
>> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
>> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
>> >> +
>> >> +    vs_dc_disable_cursor_plane(dc, vs_plane, old_state);
>> >> +}
>> >> +
>> >> +const struct drm_plane_helper_funcs primary_plane_helpers = {
>> >> +    .atomic_check   = vs_plane_atomic_check,
>> >> +    .atomic_update  = vs_plane_atomic_update,
>> >> +    .atomic_disable = vs_plane_atomic_disable,
>> >> +};
>> >> +
>> >> +const struct drm_plane_helper_funcs overlay_plane_helpers = {
>> >> +    .atomic_check   = vs_plane_atomic_check,
>> >> +    .atomic_update  = vs_plane_atomic_update,
>> >> +    .atomic_disable = vs_plane_atomic_disable,
>> >> +};
>> >> +
>> >> +const struct drm_plane_helper_funcs cursor_plane_helpers = {
>> >> +    .atomic_check   = vs_cursor_plane_atomic_check,
>> >> +    .atomic_update  = vs_cursor_plane_atomic_update,
>> >> +    .atomic_disable = vs_cursor_plane_atomic_disable,
>> >> +};
>> >> +
>> >> +static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
>> >> +    { VS_DEGAMMA_DISABLE,   "disabled" },
>> >> +    { VS_DEGAMMA_BT709,     "preset degamma for BT709" },
>> >> +    { VS_DEGAMMA_BT2020,    "preset degamma for BT2020" },
>> >> +};
>> >> +
>> >> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
>> >> +                             struct vs_plane_info *info,
>> >> +                             unsigned int layer_num,
>> >> +                             unsigned int possible_crtcs)
>> >> +{
>> >> +    struct vs_plane *plane;
>> >> +    int ret;
>> >> +
>> >> +    if (!info)
>> >> +            return NULL;
>> >> +
>> >> +    plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
>> >> +                                       possible_crtcs,
>> >> +                                       &vs_plane_funcs,
>> >> +                                       info->formats, info->num_formats,
>> >> +                                       info->modifiers, info->type,
>> >> +                                       info->name ? info->name : NULL);
>> >> +    if (IS_ERR(plane))
>> >> +            return ERR_CAST(plane);
>> >> +
>> >> +    if (info->type == DRM_PLANE_TYPE_PRIMARY)
>> >> +            drm_plane_helper_add(&plane->base, &primary_plane_helpers);
>> >> +    else if (info->type == DRM_PLANE_TYPE_CURSOR)
>> >> +            drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
>> >> +    else
>> >> +            drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
>> >> +
>> >> +    /* Set up the plane properties */
>> >> +    if (info->degamma_size) {
>> >> +            plane->degamma_mode =
>> >> +            drm_property_create_enum(drm_dev, 0,
>> >> +                                     "DEGAMMA_MODE",
>> >> +                                     vs_degamma_mode_enum_list,
>> >> +                                     ARRAY_SIZE(vs_degamma_mode_enum_list));
>> >> +
>> >> +            if (!plane->degamma_mode)
>> >> +                    return NULL;
>> >> +
>> >> +            drm_object_attach_property(&plane->base.base,
>> >> +                                       plane->degamma_mode,
>> >> +                                       VS_DEGAMMA_DISABLE);
>> >> +    }
>> >> +
>> >> +    if (info->rotation) {
>> >> +            ret = drm_plane_create_rotation_property(&plane->base,
>> >> +                                                     DRM_MODE_ROTATE_0,
>> >> +                                                     info->rotation);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +    }
>> >> +
>> >> +    if (info->blend_mode) {
>> >> +            ret = drm_plane_create_blend_mode_property(&plane->base,
>> >> +                                                       info->blend_mode);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +            ret = drm_plane_create_alpha_property(&plane->base);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +    }
>> >> +
>> >> +    if (info->color_encoding) {
>> >> +            ret = drm_plane_create_color_properties(&plane->base,
>> >> +                                                    info->color_encoding,
>> >> +                                                    BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
>> >> +                                                    DRM_COLOR_YCBCR_BT709,
>> >> +                                                    DRM_COLOR_YCBCR_LIMITED_RANGE);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +    }
>> >> +
>> >> +    if (info->zpos != 255) {
>> >> +            ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
>> >> +                                                 layer_num - 1);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +    } else {
>> >> +            ret = drm_plane_create_zpos_immutable_property(&plane->base,
>> >> +                                                           info->zpos);
>> >> +            if (ret)
>> >> +                    return NULL;
>> >> +    }
>> >> +
>> >> +    if (info->watermark) {
>> >> +            plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
>> >> +                                                        "WATERMARK", 0);
>> >> +            if (!plane->watermark_prop)
>> >> +                    return NULL;
>> >> +            drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
>> >> +    }
>> >> +
>> >> +    if (info->color_mgmt) {
>> >> +            plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
>> >> +                                                         "COLOR_CONFIG", 0);
>> >> +            if (!plane->color_mgmt_prop)
>> >> +                    return NULL;
>> >> +
>> >> +            drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
>> >> +    }
>> >> +
>> >> +    if (info->roi) {
>> >> +            plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
>> >> +                                                  "ROI", 0);
>> >> +            if (!plane->roi_prop)
>> >> +                    return NULL;
>> >> +
>> >> +            drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
>> >> +    }
>> >> +
>> >> +    return plane;
>> >> +}
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
>> >> new file mode 100644
>> >> index 000000000..554b74e96
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_plane.h
>> >> @@ -0,0 +1,58 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#ifndef __VS_PLANE_H__
>> >> +#define __VS_PLANE_H__
>> >> +
>> >> +#include <drm/drm_fourcc.h>
>> >> +#include <drm/drm_plane_helper.h>
>> >> +
>> >> +#include "vs_type.h"
>> >> +
>> >> +struct vs_plane_status {
>> >> +    u32 tile_mode;
>> >> +    struct drm_rect src;
>> >> +    struct drm_rect dest;
>> >> +};
>> >> +
>> >> +struct vs_plane_state {
>> >> +    struct drm_plane_state base;
>> >> +    struct vs_plane_status status; /* for debugfs */
>> >> +
>> >> +    struct drm_property_blob *watermark;
>> >> +    struct drm_property_blob *color_mgmt;
>> >> +    struct drm_property_blob *roi;
>> >> +    dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES];
>> >> +
>> >> +    u32 degamma;
>> >> +    bool degamma_changed;
>> >> +};
>> >> +
>> >> +struct vs_plane {
>> >> +    struct drm_plane base;
>> >> +    u8 id;
>> >> +
>> >> +    struct drm_property *degamma_mode;
>> >> +    struct drm_property *watermark_prop;
>> >> +    struct drm_property *color_mgmt_prop;
>> >> +    struct drm_property *roi_prop;
>> >> +};
>> >> +
>> >> +struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
>> >> +                             struct vs_plane_info *info,
>> >> +                             unsigned int layer_num,
>> >> +                             unsigned int possible_crtcs);
>> >> +
>> >> +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
>> >> +{
>> >> +    return container_of(plane, struct vs_plane, base);
>> >> +}
>> >> +
>> >> +static inline struct vs_plane_state *
>> >> +to_vs_plane_state(struct drm_plane_state *state)
>> >> +{
>> >> +    return container_of(state, struct vs_plane_state, base);
>> >> +}
>> >> +#endif /* __VS_PLANE_H__ */
>> >> diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
>> >> new file mode 100644
>> >> index 000000000..7d3378e29
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/verisilicon/vs_type.h
>> >> @@ -0,0 +1,69 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> +/*
>> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
>> >> + */
>> >> +
>> >> +#ifndef __VS_TYPE_H__
>> >> +#define __VS_TYPE_H__
>> >> +
>> >> +#include <drm/drm_plane.h>
>> >> +#include <drm/drm_plane_helper.h>
>> >> +
>> >> +struct vs_plane_info {
>> >> +    const char *name;
>> >> +    u8 id;
>> >> +    enum drm_plane_type type;
>> >> +    unsigned int num_formats;
>> >> +    const u32 *formats;
>> >> +    u8 num_modifiers;
>> >> +    const u64 *modifiers;
>> >> +    unsigned int min_width;
>> >> +    unsigned int min_height;
>> >> +    unsigned int max_width;
>> >> +    unsigned int max_height;
>> >> +    unsigned int rotation;
>> >> +    unsigned int blend_mode;
>> >> +    unsigned int color_encoding;
>> >> +
>> >> +    /* 0 means no de-gamma LUT */
>> >> +    unsigned int degamma_size;
>> >> +
>> >> +    int min_scale; /* 16.16 fixed point */
>> >> +    int max_scale; /* 16.16 fixed point */
>> >> +
>> >> +    /* default zorder value,
>> >> +     * and 255 means unsupported zorder capability
>> >> +     */
>> >> +    u8       zpos;
>> >> +
>> >> +    bool watermark;
>> >> +    bool color_mgmt;
>> >> +    bool roi;
>> >> +};
>> >> +
>> >> +struct vs_dc_info {
>> >> +    const char *name;
>> >> +
>> >> +    u8 panel_num;
>> >> +
>> >> +    /* planes */
>> >> +    u8 plane_num;
>> >> +    const struct vs_plane_info *planes;
>> >> +
>> >> +    u8 layer_num;
>> >> +    unsigned int max_bpc;
>> >> +    unsigned int color_formats;
>> >> +
>> >> +    /* 0 means no gamma LUT */
>> >> +    u16 gamma_size;
>> >> +    u8 gamma_bits;
>> >> +
>> >> +    u16 pitch_alignment;
>> >> +
>> >> +    bool pipe_sync;
>> >> +    bool background;
>> >> +    bool panel_sync;
>> >> +    bool cap_dec;
>> >> +};
>> >> +
>> >> +#endif /* __VS_TYPE_H__ */
>> >
> 
> 
>
Keith Zhao Nov. 15, 2023, 2:52 p.m. UTC | #4
On 2023/10/25 21:57, Maxime Ripard wrote:
> On Wed, Oct 25, 2023 at 06:39:56PM +0800, Keith Zhao wrote:
>> +static struct drm_crtc_state *
>> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc_state *ori_state;
>> +	struct vs_crtc_state *state;
>> +
>> +	if (!crtc->state)
>> +		return NULL;
>> +
>> +	ori_state = to_vs_crtc_state(crtc->state);
>> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +	if (!state)
>> +		return NULL;
>> +
>> +	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
>> +
>> +	state->output_fmt = ori_state->output_fmt;
> 
> That field is never set in your patch.
> 
>> +	state->encoder_type = ori_state->encoder_type;
> 
> That isn't either, and it's not clear why you would need the
> encoder_type stored in the CRTC?
> 
>> +	state->bpp = ori_state->bpp;
> 
> You seem to derive that from output_fmt, it doesn't need to be in the
> CRTC state.
> 
>> +	state->underflow = ori_state->underflow;
> 
> Assuming you're setting this from the interrupt handler, it's unsafe,
> you shouldn't do that. What are you using it for?
I am going to use the crtc_debugfs function for printing.
crtc_debugfs  will use it
But now I'd better delete it

> 
>> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
>> +	{ VS_SINGLE_DC,				"single dc mode" },
>> +	{ VS_MULTI_DC_PRIMARY,		"primary dc for multi dc mode" },
>> +	{ VS_MULTI_DC_SECONDARY,	"secondary dc for multi dc mode" },
>> +};
> 
> Custom driver properties are a no-go:
> https://docs.kernel.org/gpu/drm-kms.html#requirements
> 
> And
> 
> https://docs.kernel.org/gpu/drm-uapi.html#open-source-userspace-requirements
> 
>> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc)
>> +{
>> +	struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
>> +	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
>> +	struct dc_hw_display display;
> 
> Why are you rolling your own structure here, if it's exactly equivalent
> to what drm_display_mode and the crtc_state provide?
My original intention was to make the hardware part purer. and 
want to decouple hardware from drm struct.

so I define the own structure  between drm and hardware.
Maybe doing this will make both the hardware and drm happy

> 
>> +void vs_dc_commit(struct vs_dc *dc)
>> +{
>> +	dc_hw_enable_shadow_register(&dc->hw, false);
>> +
>> +	dc_hw_commit(&dc->hw);
>> +
>> +	if (dc->first_frame)
>> +		dc->first_frame = false;
>> +
>> +	dc_hw_enable_shadow_register(&dc->hw, true);
>> +}
> 
> It's not clear to me what you're trying to do here, does the hardware
> have latched registers that are only updated during vblank?
> 
>> +static int dc_bind(struct device *dev, struct device *master, void *data)
>> +{
>> +	struct drm_device *drm_dev = data;
>> +	struct vs_dc *dc = dev_get_drvdata(dev);
>> +	struct device_node *port;
>> +	struct vs_crtc *crtc;
>> +	struct vs_dc_info *dc_info;
>> +	struct vs_plane *plane;
>> +	struct vs_plane_info *plane_info;
>> +	int i, ret;
>> +	u32 ctrc_mask = 0;
>> +
>> +	if (!drm_dev || !dc) {
>> +		dev_err(dev, "devices are not created.\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	ret = dc_init(dev);
>> +	if (ret < 0) {
>> +		drm_err(drm_dev, "Failed to initialize DC hardware.\n");
>> +		return ret;
>> +	}
>> +
>> +	port = of_get_child_by_name(dev->of_node, "port");
>> +	if (!port) {
>> +		drm_err(drm_dev, "no port node found\n");
>> +		return -ENODEV;
>> +	}
>> +	of_node_put(port);
>> +
>> +	dc_info = dc->hw.info;
>> +
>> +	for (i = 0; i < dc_info->panel_num; i++) {
>> +		crtc = vs_crtc_create(drm_dev, dc_info);
>> +		if (!crtc) {
>> +			drm_err(drm_dev, "Failed to create CRTC.\n");
>> +			ret = -ENOMEM;
>> +			return ret;
>> +		}
>> +
>> +		crtc->base.port = port;
>> +		crtc->dev = dev;
>> +		dc->crtc[i] = crtc;
>> +		ctrc_mask |= drm_crtc_mask(&crtc->base);
>> +	}
>> +
>> +	for (i = 0; i < dc_info->plane_num; i++) {
>> +		plane_info = (struct vs_plane_info *)&dc_info->planes[i];
>> +
>> +		if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
>> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
>> +						drm_crtc_mask(&dc->crtc[0]->base));
>> +		} else if (!strcmp(plane_info->name, "Primary_1") ||
>> +				   !strcmp(plane_info->name, "Cursor_1")) {
> 
> Please use an enum and an id there.
> 
>> +static int vs_plane_atomic_set_property(struct drm_plane *plane,
>> +					struct drm_plane_state *state,
>> +					struct drm_property *property,
>> +					uint64_t val)
>> +{
>> +	struct drm_device *dev = plane->dev;
>> +	struct vs_plane *vs_plane = to_vs_plane(plane);
>> +	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
>> +	int ret = 0;
>> +
>> +	if (property == vs_plane->degamma_mode) {
>> +		if (vs_plane_state->degamma != val) {
>> +			vs_plane_state->degamma = val;
>> +			vs_plane_state->degamma_changed = true;
>> +		} else {
>> +			vs_plane_state->degamma_changed = false;
>> +		}
>> +	} else if (property == vs_plane->watermark_prop) {
>> +		ret = _vs_plane_set_property_blob_from_id(dev,
>> +							  &vs_plane_state->watermark,
>> +							  val,
>> +							  sizeof(struct drm_vs_watermark));
>> +		return ret;
>> +	} else if (property == vs_plane->color_mgmt_prop) {
>> +		ret = _vs_plane_set_property_blob_from_id(dev,
>> +							  &vs_plane_state->color_mgmt,
>> +							  val,
>> +							  sizeof(struct drm_vs_color_mgmt));
>> +		return ret;
>> +	} else if (property == vs_plane->roi_prop) {
>> +		ret = _vs_plane_set_property_blob_from_id(dev,
>> +							  &vs_plane_state->roi,
>> +							  val,
>> +							  sizeof(struct drm_vs_roi));
>> +		return ret;
>> +	} else {
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
> 
> Same story than above for properties
> 
> 
> Honestly, that driver is pretty massive, and you should be simplifying
> it a lot of you want the initial contribution to be as smooth as
> possible.
> 
> Things like all the tiling formats, the underflowing handling, all those
> properties, etc can (and should) be added in a second step once the
> foundations are in.
> 
> Maxime

ok , Thanks for reminding me. I will clarify my next goal and be more likely to simplify features.
Dmitry Baryshkov Nov. 15, 2023, 4 p.m. UTC | #5
On Wed, 15 Nov 2023 at 15:30, Keith Zhao <keith.zhao@starfivetech.com> wrote:
>
>
>
> On 2023/11/14 18:59, Dmitry Baryshkov wrote:
> > On Tue, 14 Nov 2023 at 12:42, Keith Zhao <keith.zhao@starfivetech.com> wrote:
> >>
> >>
> >>
> >> On 2023/10/26 3:28, Dmitry Baryshkov wrote:
> >> > On 25/10/2023 13:39, Keith Zhao wrote:
> >> >> add 2 crtcs and 8 planes in vs-drm
> >> >>
> >> >> Signed-off-by: Keith Zhao <keith.zhao@starfivetech.com>
> >> >> ---
> >> >>   drivers/gpu/drm/verisilicon/Makefile   |    8 +-
> >> >>   drivers/gpu/drm/verisilicon/vs_crtc.c  |  257 ++++
> >> >>   drivers/gpu/drm/verisilicon/vs_crtc.h  |   43 +
> >> >>   drivers/gpu/drm/verisilicon/vs_dc.c    | 1002 ++++++++++++
> >> >>   drivers/gpu/drm/verisilicon/vs_dc.h    |   80 +
> >> >>   drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1959 ++++++++++++++++++++++++
> >> >>   drivers/gpu/drm/verisilicon/vs_dc_hw.h |  492 ++++++
> >> >>   drivers/gpu/drm/verisilicon/vs_drv.c   |    2 +
> >> >>   drivers/gpu/drm/verisilicon/vs_plane.c |  526 +++++++
> >> >>   drivers/gpu/drm/verisilicon/vs_plane.h |   58 +
> >> >>   drivers/gpu/drm/verisilicon/vs_type.h  |   69 +
> >> >>   11 files changed, 4494 insertions(+), 2 deletions(-)
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h
> >> >>   create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h
> >> >>
> >> >> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
> >> >> index 7d3be305b..1d48016ca 100644
> >> >> --- a/drivers/gpu/drm/verisilicon/Makefile
> >> >> +++ b/drivers/gpu/drm/verisilicon/Makefile
> >> >> @@ -1,7 +1,11 @@
> >> >>   # SPDX-License-Identifier: GPL-2.0
> >> >>
> >> >> -vs_drm-objs := vs_drv.o \
> >> >> -            vs_modeset.o
> >> >> +vs_drm-objs := vs_dc_hw.o \
> >> >> +            vs_dc.o \
> >> >> +            vs_crtc.o \
> >> >> +            vs_drv.o \
> >> >> +            vs_modeset.o \
> >> >> +            vs_plane.o
> >> >>
> >> >>   obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
> >> >>
> >> >> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
> >> >> new file mode 100644
> >> >> index 000000000..8a658ea77
> >> >> --- /dev/null
> >> >> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
> >> >> @@ -0,0 +1,257 @@
> >> >> +// SPDX-License-Identifier: GPL-2.0
> >> >> +/*
> >> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> >> >> + *
> >> >> + */
> >> >> +
> >> >> +#include <linux/clk.h>
> >> >> +#include <linux/debugfs.h>
> >> >> +#include <linux/media-bus-format.h>
> >> >> +
> >> >> +#include <drm/drm_atomic_helper.h>
> >> >> +#include <drm/drm_atomic.h>
> >> >> +#include <drm/drm_crtc.h>
> >> >> +#include <drm/drm_gem_atomic_helper.h>
> >> >> +#include <drm/drm_vblank.h>
> >> >> +#include <drm/vs_drm.h>
> >> >> +
> >> >> +#include "vs_crtc.h"
> >> >> +#include "vs_dc.h"
> >> >> +#include "vs_drv.h"
> >> >> +
> >> >> +static void vs_crtc_reset(struct drm_crtc *crtc)
> >> >> +{
> >> >> +    struct vs_crtc_state *state;
> >> >> +
> >> >> +    if (crtc->state) {
> >> >> +            __drm_atomic_helper_crtc_destroy_state(crtc->state);
> >> >> +
> >> >> +            state = to_vs_crtc_state(crtc->state);
> >> >> +            kfree(state);
> >> >> +            crtc->state = NULL;
> >> >> +    }
> >> >
> >> > You can call your crtc_destroy_state function directly here.
> >> >
> >> >> +
> >> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
> >> >> +    if (!state)
> >> >> +            return;
> >> >> +
> >> >> +    __drm_atomic_helper_crtc_reset(crtc, &state->base);
> >> >> +}
> >> >> +
> >> >> +static struct drm_crtc_state *
> >> >> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
> >> >> +{
> >> >> +    struct vs_crtc_state *ori_state;
> >> >
> >> > It might be a matter of taste, but it is usually old_state.
> >> >
> >> >> +    struct vs_crtc_state *state;
> >> >> +
> >> >> +    if (!crtc->state)
> >> >> +            return NULL;
> >> >> +
> >> >> +    ori_state = to_vs_crtc_state(crtc->state);
> >> >> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
> >> >> +    if (!state)
> >> >> +            return NULL;
> >> >> +
> >> >> +    __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
> >> >> +
> >> >> +    state->output_fmt = ori_state->output_fmt;
> >> >> +    state->encoder_type = ori_state->encoder_type;
> >> >> +    state->bpp = ori_state->bpp;
> >> >> +    state->underflow = ori_state->underflow;
> >> >
> >> > Can you use kmemdup instead?
> >> >
> >> >> +
> >> >> +    return &state->base;
> >> >> +}
> >> >> +
> >> >> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
> >> >> +                                     struct drm_crtc_state *state)
> >> >> +{
> >> >> +    __drm_atomic_helper_crtc_destroy_state(state);
> >> >> +    kfree(to_vs_crtc_state(state));
> >> >> +}
> >> >> +
> >> >> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
> >> >> +{
> >> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> >> +
> >> >> +    vs_dc_enable_vblank(dc, true);
> >> >> +
> >> >> +    return 0;
> >> >> +}
> >> >> +
> >> >> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
> >> >> +{
> >> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> >> +
> >> >> +    vs_dc_enable_vblank(dc, false);
> >> >> +}
> >> >> +
> >> >> +static const struct drm_crtc_funcs vs_crtc_funcs = {
> >> >> +    .set_config             = drm_atomic_helper_set_config,
> >> >> +    .page_flip              = drm_atomic_helper_page_flip,
> >> >
> >> > destroy is required, see drm_mode_config_cleanup()
> >>
> >> hi Dmitry:
> >> if define destroy in drm_crtc_funcs,
> >> it will make __drmm_crtc_init_with_planes unhappy
> >
> > Ack, I missed that you have been using drmm_crtc_init. BTW, I checked
> > your code, you should be able to switch drm
> > drmm_crtc_alloc_with_planes().
> >
> yes
> I done the replace and it can work well.
>
> >>
> >> see:
> >> __printf(6, 0)
> >> static int __drmm_crtc_init_with_planes(struct drm_device *dev,
> >>                                         struct drm_crtc *crtc,
> >>                                         struct drm_plane *primary,
> >>                                         struct drm_plane *cursor,
> >>                                         const struct drm_crtc_funcs *funcs,
> >>                                         const char *name,
> >>                                         va_list args)
> >> {
> >>         int ret;
> >>
> >>         drm_WARN_ON(dev, funcs && funcs->destroy);
> >>
> >> ........
> >> }
> >>
> >> It should not need to be defined here, I think
> >>
> >> >
> >> >> +    .reset                  = vs_crtc_reset,
> >> >> +    .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
> >> >> +    .atomic_destroy_state   = vs_crtc_atomic_destroy_state,
> >> >
> >> > please consider adding atomic_print_state to output driver-specific bits.
> >> >
> >> >> +    .enable_vblank          = vs_crtc_enable_vblank,
> >> >> +    .disable_vblank         = vs_crtc_disable_vblank,
> >> >> +};
> >> >> +
> >> >> +static u8 cal_pixel_bits(u32 bus_format)
> >> >
> >> > This looks like a generic helper code, which can go to a common place.
> I don't know if I understand correctly
> Here I remove static
> Add 2 lines in vs_drv.h
>
> /* vs_crtc.c */
> u8 cal_pixel_bits(u32 bus_format);
>
> to make it common

I mean, move it to a generic location, like include/media/

>
> >> >
> >> >> +{
> >> >> +    u8 bpp;
> >> >> +
> >> >> +    switch (bus_format) {
> >> >> +    case MEDIA_BUS_FMT_RGB565_1X16:
> >> >> +    case MEDIA_BUS_FMT_UYVY8_1X16:
> >> >> +            bpp = 16;
> >> >> +            break;
> >> >> +    case MEDIA_BUS_FMT_RGB666_1X18:
> >> >> +    case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> >> >> +            bpp = 18;
> >> >> +            break;
> >> >> +    case MEDIA_BUS_FMT_UYVY10_1X20:
> >> >> +            bpp = 20;
> >> >> +            break;
> >> >> +    case MEDIA_BUS_FMT_BGR888_1X24:
> >> >> +    case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> >> >> +    case MEDIA_BUS_FMT_YUV8_1X24:
> >> >> +            bpp = 24;
> >> >> +            break;
> >> >> +    case MEDIA_BUS_FMT_RGB101010_1X30:
> >> >> +    case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> >> >> +    case MEDIA_BUS_FMT_YUV10_1X30:
> >> >> +            bpp = 30;
> >> >> +            break;
> >> >> +    default:
> >> >> +            bpp = 24;
> >> >> +            break;
> >> >> +    }
> >> >> +
> >> >> +    return bpp;
> >> >> +}
> >> >> +

[skipped]

> >> >> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> >> >> +                           struct vs_dc_info *info)
> >> >> +{
> >> >> +    struct vs_crtc *crtc;
> >> >> +    int ret;
> >> >> +
> >> >> +    if (!info)
> >> >> +            return NULL;
> >> >> +
> >> >> +    crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL);
> >> >> +    if (!crtc)
> >> >> +            return NULL;
> >> >> +
> >> >> +    ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base,
> >> >> +                                     NULL, NULL, &vs_crtc_funcs,
> >> >> +                                     info->name ? info->name : NULL);
> >> >
> >> > It might be better to add drmm_crtc_init() helper.
>         drmm_crtc_alloc_with_planes used:
>         ...
>         struct vs_crtc *crtc;
>         int ret;
>
>         if (!info)
>                 return NULL;
>
>         crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base,
>                                                NULL, NULL,
>                                                &vs_crtc_funcs, info->name ? info->name : NULL);
>         ...

Ack.

>
> >> >
> >> >> +    if (ret)
> >> >> +            return NULL;
> >> >> +
> >> >> +    drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
> >> >> +
> >> >> +    if (info->gamma_size) {
> >> >> +            ret = drm_mode_crtc_set_gamma_size(&crtc->base,
> >> >> +                                               info->gamma_size);
> >> >> +            if (ret)
> >> >> +                    return NULL;
> >> >> +
> >> >> +            drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
> >> >> +                                       info->gamma_size);
> >> >> +    }
> >> >> +
> >> >> +    crtc->max_bpc = info->max_bpc;
> >> >> +    crtc->color_formats = info->color_formats;
> >> >> +    return crtc;
> >> >> +}

> >> >> +const struct component_ops dc_component_ops = {
> >> >> +    .bind = dc_bind,
> >> >> +    .unbind = dc_unbind,
> >> >> +};
> >> >> +
> >> >> +static const struct of_device_id dc_driver_dt_match[] = {
> >> >> +    { .compatible = "starfive,jh7110-dc8200", },
> >> >> +    {},
> >> >> +};
> >> >> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
> >> >> +
> >> >> +static int dc_probe(struct platform_device *pdev)
> >> >> +{
> >> >> +    struct device *dev = &pdev->dev;
> >> >> +    struct vs_dc *dc;
> >> >> +    int irq, ret, i;
> >> >> +
> >> >> +    dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
> >> >> +    if (!dc)
> >> >> +            return -ENOMEM;
> >> >> +
> >> >> +    dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
> >> >> +    if (IS_ERR(dc->hw.hi_base))
> >> >> +            return PTR_ERR(dc->hw.hi_base);
> >> >> +
> >> >> +    dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
> >> >> +    if (IS_ERR(dc->hw.reg_base))
> >> >> +            return PTR_ERR(dc->hw.reg_base);
> >> >> +
> >> >> +    dc->nclks = ARRAY_SIZE(dc->clk_vout);
> >> >> +    for (i = 0; i < dc->nclks; ++i)
> >> >> +            dc->clk_vout[i].id = vout_clocks[i];
> >> >> +    ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
> >> >> +    if (ret) {
> >> >> +            dev_err(dev, "Failed to get clk controls\n");
> >> >> +            return ret;
> >> >> +    }
> >> >> +
> >> >> +    dc->nrsts = ARRAY_SIZE(dc->rst_vout);
> >> >> +    for (i = 0; i < dc->nrsts; ++i)
> >> >> +            dc->rst_vout[i].id = vout_resets[i];
> >> >> +    ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
> >> >> +                                             dc->rst_vout);
> >> >> +    if (ret) {
> >> >> +            dev_err(dev, "Failed to get reset controls\n");
> >> >> +            return ret;
> >> >> +    }
> >> >> +
> >> >> +    irq = platform_get_irq(pdev, 0);
> >> >> +
> >> >> +    ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
> >> >
> >> > Are you ready to handle the IRQ at this point?
> Do you have some good suggestions?
> Are there any hidden dangers in doing so?


If your driver is not ready, stray interrupt can crash your driver.
For pm_runtime-enabled devices it is even more important: the
interrupt handled might try accessing device which is powered off.

> Hope to get good opinions

The usual suggestion is: request the interrupt when your data is fully
set up. Or request_irq with IRQF_NO_AUTOEN and then enable_irq() /
disable_irq() as required.

>
> >> >
> >> >> +    if (ret < 0) {
> >> >> +            dev_err(dev, "Failed to install irq:%u.\n", irq);
> >> >> +            return ret;
> >> >> +    }
> >> >> +
> >> >> +    dev_set_drvdata(dev, dc);
> >> >> +
> >> >> +    return component_add(dev, &dc_component_ops);
> >> >> +}
> >> >> +

[skipped]

> >> >> +static int vs_plane_atomic_get_property(struct drm_plane *plane,
> >> >> +                                    const struct drm_plane_state *state,
> >> >> +                                    struct drm_property *property,
> >> >> +                                    uint64_t *val)
> >> >> +{
> >> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> >> +    const struct vs_plane_state *vs_plane_state =
> >> >> +            container_of(state, const struct vs_plane_state, base);
> >> >> +
> >> >> +    if (property == vs_plane->degamma_mode)
> >> >> +            *val = vs_plane_state->degamma;
> >> >> +    else if (property == vs_plane->watermark_prop)
> >> >> +            *val = (vs_plane_state->watermark) ?
> >> >> +                                    vs_plane_state->watermark->base.id : 0;
> >> >> +    else if (property == vs_plane->color_mgmt_prop)
> >> >> +            *val = (vs_plane_state->color_mgmt) ?
> >> >> +                                    vs_plane_state->color_mgmt->base.id : 0;
> >> >
> >> > degamma and color management should use standard properties.
>
> hello Dmitry:
> There is a question that troubles me
>
> drm_plane include such standard properties.
> {
>         struct drm_property *alpha_property;
>         struct drm_property *zpos_property;
>         struct drm_property *rotation_property;
>         struct drm_property *blend_mode_property;
>         struct drm_property *color_encoding_property;
>         struct drm_property *color_range_property;
>         struct drm_property *scaling_filter_property;
> }
>
> it doesn't include degamma and color management properties

Which is because they are not standardised yet.

>
> >> >
> >> >> +    else if (property == vs_plane->roi_prop)
> >> >> +            *val = (vs_plane_state->roi) ?
> >> >> +                                    vs_plane_state->roi->base.id : 0;
> >> >> +    else
> >> >> +            return -EINVAL;
> >> >> +
> >> >> +    return 0;
> >> >> +}
> >> >> +
> >> >> +static bool vs_format_mod_supported(struct drm_plane *plane,
> >> >> +                                u32 format,
> >> >> +                                u64 modifier)
> >> >> +{
> >> >> +    int i;
> >> >> +
> >> >> +    /* We always have to allow these modifiers:
> >> >> +     * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
> >> >> +     * 2. Not passing any modifiers is the same as explicitly passing INVALID.
> >> >> +     */
> >> >> +    if (modifier == DRM_FORMAT_MOD_LINEAR)
> >> >> +            return true;
> >> >> +
> >> >> +    /* Check that the modifier is on the list of the plane's supported modifiers. */
> >> >> +    for (i = 0; i < plane->modifier_count; i++) {
> >> >> +            if (modifier == plane->modifiers[i])
> >> >> +                    break;
> >> >> +    }
> >> >> +
> >> >> +    if (i == plane->modifier_count)
> >> >> +            return false;
> >> >> +
> >> >> +    return true;
> >> >> +}
> >> >> +
> >> >> +const struct drm_plane_funcs vs_plane_funcs = {
> >> >> +    .update_plane           = drm_atomic_helper_update_plane,
> >> >> +    .disable_plane          = drm_atomic_helper_disable_plane,
> >> >> +    .reset                  = vs_plane_reset,
> >> >> +    .atomic_duplicate_state = vs_plane_atomic_duplicate_state,
> >> >> +    .atomic_destroy_state   = vs_plane_atomic_destroy_state,
> >> >> +    .atomic_set_property    = vs_plane_atomic_set_property,
> >> >> +    .atomic_get_property    = vs_plane_atomic_get_property,
> >> >> +    .format_mod_supported   = vs_format_mod_supported,
> >> >> +};
> >> >> +
> >> >> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
> >> >> +{
> >> >> +    const struct drm_format_info *info;
> >> >> +
> >> >> +    if (!fb)
> >> >> +            return 0;
> >> >> +
> >> >> +    info = drm_format_info(fb->format->format);
> >> >> +    if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
> >> >> +            return 0;
> >> >> +
> >> >> +    return info->num_planes;
> >> >> +}
> >> >> +
> >> >> +static int vs_plane_atomic_check(struct drm_plane *plane,
> >> >> +                             struct drm_atomic_state *state)
> >> >> +{
> >> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >> >> +                                                                             plane);
> >> >> +    unsigned char i, num_planes;
> >> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
> >> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
> >> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
> >> >> +
> >> >> +    if (!crtc || !fb)
> >> >> +            return 0;
> >> >> +
> >> >> +    num_planes = vs_get_plane_number(fb);
> >> >> +
> >> >> +    for (i = 0; i < num_planes; i++) {
> >> >> +            dma_addr_t dma_addr;
> >> >> +
> >> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
> >> >> +            plane_state->dma_addr[i] = dma_addr;
> >> >> +    }
> >> >> +
> >> >> +    return vs_dc_check_plane(dc, plane, state);
> >> >> +}
> >> >> +
> >> >> +static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
> >> >> +                                    struct drm_atomic_state *state)
> >> >> +{
> >> >> +    struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> >> >> +                                                                      plane);
> >> >> +    unsigned char i, num_planes;
> >> >> +    struct drm_framebuffer *fb = new_plane_state->fb;
> >> >> +    struct drm_crtc *crtc = new_plane_state->crtc;
> >> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> >> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
> >> >> +
> >> >> +    if (!crtc || !fb)
> >> >> +            return 0;
> >> >> +
> >> >> +    num_planes = vs_get_plane_number(fb);
> >> >> +
> >> >> +    for (i = 0; i < num_planes; i++) {
> >> >> +            dma_addr_t dma_addr;
> >> >> +
> >> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
> >> >> +            plane_state->dma_addr[i] = dma_addr;
> >> >> +    }
> >> >> +
> >> >> +    return vs_dc_check_cursor_plane(dc, plane, state);
> >> >> +}
> >> >> +
> >> >> +static void vs_plane_atomic_update(struct drm_plane *plane,
> >> >> +                               struct drm_atomic_state *state)
> >> >> +{
> >> >> +    struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> >> >> +                                                                      plane);
> >> >
> >> > New line after the equal sign will be better.
> >> >
> >> >> +    struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
> >> >> +                                                                      plane);
> >> >> +
> >> >> +    unsigned char i, num_planes;
> >> >> +    struct drm_framebuffer *fb;
> >> >> +    struct vs_plane *vs_plane = to_vs_plane(plane);
> >> >> +    struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
> >> >> +    struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
> >> >> +    struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> >> >> +
> >> >> +    if (!new_state->fb || !new_state->crtc)
> >> >> +            return;
> >> >
> >> > if (!new_state->visible) ?
>
> no matter what value it is ? the driver will handle it
> in func
>
> static void update_fb(struct vs_plane *plane, u8 display_id,
>                       struct dc_hw_fb *fb, struct drm_plane_state *state)
> {
>         struct vs_plane_state *plane_state = to_vs_plane_state(state);
>         struct drm_framebuffer *drm_fb = state->fb;
>         struct drm_rect *src = &state->src;
>
> .......
>         fb->enable = state->visible;
> .......
> }
>
> so no need add "if (!new_state->visible)" i think

I mean instead of fb&&crtc check. Otherwise you are duplicating checks
in drm_atomic_helper_check_plane_state(). And with the pixel_source
being on their way this condition becomes legacy.

>
> >> >
> >> >> +
> >> >> +    fb = new_state->fb;
> >> >> +
> >> >> +    drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
> >> >> +
> >> >> +    num_planes = vs_get_plane_number(fb);
> >> >> +
> >> >> +    for (i = 0; i < num_planes; i++) {
> >> >> +            dma_addr_t dma_addr;
> >> >> +
> >> >> +            dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
> >> >> +            plane_state->dma_addr[i] = dma_addr;
> >> >> +    }
> >> >> +
> >> >> +    plane_state->status.src = drm_plane_state_src(new_state);
> >> >> +    plane_state->status.dest = drm_plane_state_dest(new_state);
> >> >> +
> >> >> +    vs_dc_update_plane(dc, vs_plane, plane, state);
> >> >> +}
> >> >> +
Thomas Zimmermann Nov. 24, 2023, 1:40 p.m. UTC | #6
Hi

Am 25.10.23 um 12:39 schrieb Keith Zhao:
[...]
> +
> +static struct drm_crtc_state *
> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc_state *ori_state;

I have not yet seen 'ori_' being used anywhere. Typical names are 
'state' for the current state and 'new_state' for the newly created 
state.  Would be nice for consistency with other drivers.

> +	struct vs_crtc_state *state;
> +
> +	if (!crtc->state)
> +		return NULL;
> +
> +	ori_state = to_vs_crtc_state(crtc->state);
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
> +
> +	state->output_fmt = ori_state->output_fmt;
> +	state->encoder_type = ori_state->encoder_type;
> +	state->bpp = ori_state->bpp;
> +	state->underflow = ori_state->underflow;
> +
> +	return &state->base;
> +}
> +
> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
> +					 struct drm_crtc_state *state)
> +{
> +	__drm_atomic_helper_crtc_destroy_state(state);
> +	kfree(to_vs_crtc_state(state));
> +}
> +
> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> +
> +	vs_dc_enable_vblank(dc, true);
> +
> +	return 0;
> +}
> +
> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> +
> +	vs_dc_enable_vblank(dc, false);
> +}
> +
> +static const struct drm_crtc_funcs vs_crtc_funcs = {
> +	.set_config		= drm_atomic_helper_set_config,
> +	.page_flip		= drm_atomic_helper_page_flip,
> +	.reset			= vs_crtc_reset,
> +	.atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
> +	.atomic_destroy_state	= vs_crtc_atomic_destroy_state,
> +	.enable_vblank		= vs_crtc_enable_vblank,
> +	.disable_vblank		= vs_crtc_disable_vblank,
> +};
> +
> +static u8 cal_pixel_bits(u32 bus_format)
> +{
> +	u8 bpp;
> +
> +	switch (bus_format) {
> +	case MEDIA_BUS_FMT_RGB565_1X16:
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +		bpp = 16;
> +		break;
> +	case MEDIA_BUS_FMT_RGB666_1X18:
> +	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
> +		bpp = 18;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY10_1X20:
> +		bpp = 20;
> +		break;
> +	case MEDIA_BUS_FMT_BGR888_1X24:
> +	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
> +	case MEDIA_BUS_FMT_YUV8_1X24:
> +		bpp = 24;
> +		break;
> +	case MEDIA_BUS_FMT_RGB101010_1X30:
> +	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
> +	case MEDIA_BUS_FMT_YUV10_1X30:
> +		bpp = 30;
> +		break;
> +	default:
> +		bpp = 24;
> +		break;
> +	}
> +
> +	return bpp;
> +}
> +
> +static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
> +				  struct drm_atomic_state *state)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
> +
> +	vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
> +
> +	vs_dc_enable(dc, crtc);
> +	drm_crtc_vblank_on(crtc);
> +}
> +
> +static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
> +				   struct drm_atomic_state *state)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> +
> +	drm_crtc_vblank_off(crtc);
> +
> +	vs_dc_disable(dc, crtc);
> +
> +	if (crtc->state->event && !crtc->state->active) {
> +		spin_lock_irq(&crtc->dev->event_lock);
> +		drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +		spin_unlock_irq(&crtc->dev->event_lock);
> +
> +		crtc->state->event = NULL;
> +	}
> +}
> +
> +static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
> +				 struct drm_atomic_state *state)
> +{
> +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> +									  crtc);
> +
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct device *dev = vs_crtc->dev;
> +	struct drm_property_blob *blob = crtc->state->gamma_lut;
> +	struct drm_color_lut *lut;
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	if (crtc_state->color_mgmt_changed) {
> +		if (blob && blob->length) {
> +			lut = blob->data;
> +			vs_dc_set_gamma(dc, crtc, lut,
> +					blob->length / sizeof(*lut));
> +			vs_dc_enable_gamma(dc, crtc, true);
> +		} else {
> +			vs_dc_enable_gamma(dc, crtc, false);
> +		}
> +	}
> +}
> +
> +static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
> +				 struct drm_atomic_state *state)
> +{
> +	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
> +	struct drm_pending_vblank_event *event = crtc->state->event;
> +	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
> +
> +	vs_dc_commit(dc);
> +
> +	if (event) {
> +		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> +
> +		spin_lock_irq(&crtc->dev->event_lock);
> +		drm_crtc_arm_vblank_event(crtc, event);
> +		spin_unlock_irq(&crtc->dev->event_lock);
> +		crtc->state->event = NULL;
> +	}
> +}
> +
> +static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
> +	.atomic_check = drm_crtc_helper_atomic_check,
> +	.atomic_enable	= vs_crtc_atomic_enable,
> +	.atomic_disable = vs_crtc_atomic_disable,
> +	.atomic_begin	= vs_crtc_atomic_begin,
> +	.atomic_flush	= vs_crtc_atomic_flush,
> +};
> +
> +static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
> +	{ VS_SINGLE_DC,				"single dc mode" },
> +	{ VS_MULTI_DC_PRIMARY,		"primary dc for multi dc mode" },
> +	{ VS_MULTI_DC_SECONDARY,	"secondary dc for multi dc mode" },
> +};
> +
> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> +			       struct vs_dc_info *info)
> +{
> +	struct vs_crtc *crtc;
> +	int ret;
> +
> +	if (!info)
> +		return NULL;
> +
> +	crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL);
> +	if (!crtc)
> +		return NULL;
> +
> +	ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base,
> +					 NULL, NULL, &vs_crtc_funcs,
> +					 info->name ? info->name : NULL);
> +	if (ret)
> +		return NULL;
> +
> +	drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
> +
> +	if (info->gamma_size) {
> +		ret = drm_mode_crtc_set_gamma_size(&crtc->base,
> +						   info->gamma_size);
> +		if (ret)
> +			return NULL;
> +
> +		drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
> +					   info->gamma_size);
> +	}
> +
> +	crtc->max_bpc = info->max_bpc;
> +	crtc->color_formats = info->color_formats;
> +	return crtc;
> +}
> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
> new file mode 100644
> index 000000000..526dd63e5
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
> @@ -0,0 +1,43 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_CRTC_H__
> +#define __VS_CRTC_H__
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include "vs_type.h"
> +
> +struct vs_crtc_state {
> +	struct drm_crtc_state base;
> +
> +	u32 output_fmt;
> +	u8 encoder_type;
> +	u8 bpp;
> +	bool underflow;
> +};
> +
> +struct vs_crtc {
> +	struct drm_crtc base;
> +	struct device *dev;
> +	unsigned int max_bpc;
> +	unsigned int color_formats;
> +};
> +
> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
> +			       struct vs_dc_info *info);
> +
> +static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
> +{
> +	return container_of(crtc, struct vs_crtc, base);
> +}
> +
> +static inline struct vs_crtc_state *
> +to_vs_crtc_state(struct drm_crtc_state *state)
> +{
> +	return container_of(state, struct vs_crtc_state, base);
> +}
> +#endif /* __VS_CRTC_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
> new file mode 100644
> index 000000000..b5ab92d98
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc.c
> @@ -0,0 +1,1002 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/component.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/reset.h>
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_blend.h>
> +#include <drm/drm_framebuffer.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/vs_drm.h>
> +
> +#include "vs_dc_hw.h"
> +#include "vs_dc.h"
> +#include "vs_drv.h"
> +
> +static const char * const vout_clocks[] = {
> +	"noc_bus",
> +	"channel0",
> +	"channel1",
> +	"dc_core",
> +	"axi_core",
> +	"ahb",
> +	"hdmi_tx",
> +	"dc_parent",
> +
> +};
> +
> +static const char * const vout_resets[] = {
> +	"axi",
> +	"ahb",
> +	"core",
> +};
> +
> +static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
> +{
> +	u8 f = FORMAT_A8R8G8B8;
> +
> +	switch (format) {
> +	case DRM_FORMAT_XRGB4444:
> +	case DRM_FORMAT_RGBX4444:
> +	case DRM_FORMAT_XBGR4444:
> +	case DRM_FORMAT_BGRX4444:
> +		f = FORMAT_X4R4G4B4;
> +		break;
> +	case DRM_FORMAT_ARGB4444:
> +	case DRM_FORMAT_RGBA4444:
> +	case DRM_FORMAT_ABGR4444:
> +	case DRM_FORMAT_BGRA4444:
> +		f = FORMAT_A4R4G4B4;
> +		break;
> +	case DRM_FORMAT_XRGB1555:
> +	case DRM_FORMAT_RGBX5551:
> +	case DRM_FORMAT_XBGR1555:
> +	case DRM_FORMAT_BGRX5551:
> +		f = FORMAT_X1R5G5B5;
> +		break;
> +	case DRM_FORMAT_ARGB1555:
> +	case DRM_FORMAT_RGBA5551:
> +	case DRM_FORMAT_ABGR1555:
> +	case DRM_FORMAT_BGRA5551:
> +		f = FORMAT_A1R5G5B5;
> +		break;
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_BGR565:
> +		f = FORMAT_R5G6B5;
> +		break;
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_RGBX8888:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_BGRX8888:
> +		f = FORMAT_X8R8G8B8;
> +		break;
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_BGRA8888:
> +		f = FORMAT_A8R8G8B8;
> +		break;
> +	case DRM_FORMAT_YUYV:
> +	case DRM_FORMAT_YVYU:
> +		f = FORMAT_YUY2;
> +		break;
> +	case DRM_FORMAT_UYVY:
> +	case DRM_FORMAT_VYUY:
> +		f = FORMAT_UYVY;
> +		break;
> +	case DRM_FORMAT_YUV420:
> +	case DRM_FORMAT_YVU420:
> +		f = FORMAT_YV12;
> +		break;
> +	case DRM_FORMAT_NV21:
> +		f = FORMAT_NV12;
> +		break;
> +	case DRM_FORMAT_NV16:
> +	case DRM_FORMAT_NV61:
> +		f = FORMAT_NV16;
> +		break;
> +	case DRM_FORMAT_P010:
> +		f = FORMAT_P010;
> +		break;
> +	case DRM_FORMAT_ARGB2101010:
> +	case DRM_FORMAT_RGBA1010102:
> +	case DRM_FORMAT_ABGR2101010:
> +	case DRM_FORMAT_BGRA1010102:
> +		f = FORMAT_A2R10G10B10;
> +		break;
> +	case DRM_FORMAT_NV12:
> +		f = FORMAT_NV12;
> +		break;
> +	case DRM_FORMAT_YUV444:
> +		f = FORMAT_YUV444;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	fb->format = f;
> +}
> +
> +static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
> +{
> +	fb->swizzle = SWIZZLE_ARGB;
> +	fb->uv_swizzle = 0;
> +
> +	switch (format) {
> +	case DRM_FORMAT_RGBX4444:
> +	case DRM_FORMAT_RGBA4444:
> +	case DRM_FORMAT_RGBX5551:
> +	case DRM_FORMAT_RGBA5551:
> +	case DRM_FORMAT_RGBX8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_RGBA1010102:
> +		fb->swizzle = SWIZZLE_RGBA;
> +		break;
> +	case DRM_FORMAT_XBGR4444:
> +	case DRM_FORMAT_ABGR4444:
> +	case DRM_FORMAT_XBGR1555:
> +	case DRM_FORMAT_ABGR1555:
> +	case DRM_FORMAT_BGR565:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_ABGR2101010:
> +		fb->swizzle = SWIZZLE_ABGR;
> +		break;
> +	case DRM_FORMAT_BGRX4444:
> +	case DRM_FORMAT_BGRA4444:
> +	case DRM_FORMAT_BGRX5551:
> +	case DRM_FORMAT_BGRA5551:
> +	case DRM_FORMAT_BGRX8888:
> +	case DRM_FORMAT_BGRA8888:
> +	case DRM_FORMAT_BGRA1010102:
> +		fb->swizzle = SWIZZLE_BGRA;
> +		break;
> +	case DRM_FORMAT_YVYU:
> +	case DRM_FORMAT_VYUY:
> +	case DRM_FORMAT_NV21:
> +	case DRM_FORMAT_NV61:
> +		fb->uv_swizzle = 1;
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static inline void update_watermark(struct drm_property_blob *watermark,
> +				    struct dc_hw_fb *fb)
> +{
> +	struct drm_vs_watermark *data;
> +
> +	fb->water_mark = 0;
> +
> +	if (watermark) {
> +		data = watermark->data;
> +		fb->water_mark = data->watermark & 0xFFFFF;
> +	}
> +}
> +
> +static inline u8 to_vs_rotation(unsigned int rotation)
> +{
> +	u8 rot;
> +
> +	switch (rotation & DRM_MODE_REFLECT_MASK) {
> +	case DRM_MODE_REFLECT_X:
> +		rot = FLIP_X;
> +		return rot;
> +	case DRM_MODE_REFLECT_Y:
> +		rot = FLIP_Y;
> +		return rot;
> +	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
> +		rot = FLIP_XY;
> +		return rot;
> +	default:
> +		break;
> +	}
> +
> +	switch (rotation & DRM_MODE_ROTATE_MASK) {
> +	case DRM_MODE_ROTATE_0:
> +		rot = ROT_0;
> +		break;
> +	case DRM_MODE_ROTATE_90:
> +		rot = ROT_90;
> +		break;
> +	case DRM_MODE_ROTATE_180:
> +		rot = ROT_180;
> +		break;
> +	case DRM_MODE_ROTATE_270:
> +		rot = ROT_270;
> +		break;
> +	default:
> +		rot = ROT_0;
> +		break;
> +	}
> +
> +	return rot;
> +}
> +
> +static inline u8 to_vs_yuv_color_space(u32 color_space)
> +{
> +	u8 cs;
> +
> +	switch (color_space) {
> +	case DRM_COLOR_YCBCR_BT601:
> +		cs = COLOR_SPACE_601;
> +		break;
> +	case DRM_COLOR_YCBCR_BT709:
> +		cs = COLOR_SPACE_709;
> +		break;
> +	case DRM_COLOR_YCBCR_BT2020:
> +		cs = COLOR_SPACE_2020;
> +		break;
> +	default:
> +		cs = COLOR_SPACE_601;
> +		break;
> +	}
> +
> +	return cs;
> +}
> +
> +static inline u8 to_vs_tile_mode(u64 modifier)
> +{
> +	if (modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
> +		return DC_TILE_MODE4X4;
> +
> +	return (u8)(modifier & DRM_FORMAT_MOD_VERISILICON_NORM_MODE_MASK);
> +}
> +
> +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
> +{
> +	u8 panel_num = dc->hw.info->panel_num;
> +	u32 index = drm_crtc_index(crtc);
> +	int i;
> +
> +	for (i = 0; i < panel_num; i++) {
> +		if (index == dc->crtc[i]->base.index)
> +			return i;
> +	}
> +
> +	return 0;
> +}
> +
> +static void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
> +					  unsigned int alignment)
> +{
> +	struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
> +
> +	if (alignment > priv->pitch_alignment)
> +		priv->pitch_alignment = alignment;
> +}
> +
> +static int plda_clk_rst_init(struct device *dev)
> +{
> +	int ret = 0;
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
> +	if (ret) {
> +		dev_err(dev, "failed to enable clocks\n");
> +		return ret;
> +	}
> +
> +	ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
> +	return ret;
> +}
> +
> +static void plda_clk_rst_deinit(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
> +	clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
> +}
> +
> +static void dc_deinit(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +
> +	dc_hw_enable_interrupt(&dc->hw, 0);
> +	dc_hw_deinit(&dc->hw);
> +	plda_clk_rst_deinit(dev);
> +}
> +
> +static int dc_init(struct device *dev)
> +{
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	int ret;
> +
> +	dc->first_frame = true;
> +
> +	ret = plda_clk_rst_init(dev);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to init dc clk reset: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = dc_hw_init(&dc->hw);
> +	if (ret) {
> +		dev_err(dev, "failed to init DC HW\n");
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc)
> +{
> +	struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
> +	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> +	struct dc_hw_display display;
> +
> +	display.bus_format = crtc_state->output_fmt;
> +	display.h_active = mode->hdisplay;
> +	display.h_total = mode->htotal;
> +	display.h_sync_start = mode->hsync_start;
> +	display.h_sync_end = mode->hsync_end;
> +	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
> +		display.h_sync_polarity = true;
> +	else
> +		display.h_sync_polarity = false;
> +
> +	display.v_active = mode->vdisplay;
> +	display.v_total = mode->vtotal;
> +	display.v_sync_start = mode->vsync_start;
> +	display.v_sync_end = mode->vsync_end;
> +
> +	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
> +		display.v_sync_polarity = true;
> +	else
> +		display.v_sync_polarity = false;
> +
> +	display.id = to_vs_display_id(dc, crtc);
> +
> +	display.enable = true;
> +
> +	if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
> +		dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
> +		clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
> +		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
> +			       dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
> +	} else {
> +		dc_hw_set_out(&dc->hw, OUT_DP, display.id);
> +		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
> +			       dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
> +	}
> +
> +	dc_hw_setup_display(&dc->hw, &display);
> +}
> +
> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc)
> +{
> +	struct dc_hw_display display;
> +
> +	display.id = to_vs_display_id(dc, crtc);
> +	display.enable = false;
> +
> +	dc_hw_setup_display(&dc->hw, &display);
> +}
> +
> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> +		     struct drm_color_lut *lut, unsigned int size)
> +{
> +	u16 i, r, g, b;
> +	u8 bits, id;
> +
> +	if (size != dc->hw.info->gamma_size) {
> +		drm_err(crtc->dev, "gamma size does not match!\n");
> +		return;
> +	}
> +
> +	id = to_vs_display_id(dc, crtc);
> +
> +	bits = dc->hw.info->gamma_bits;
> +	for (i = 0; i < size; i++) {
> +		r = drm_color_lut_extract(lut[i].red, bits);
> +		g = drm_color_lut_extract(lut[i].green, bits);
> +		b = drm_color_lut_extract(lut[i].blue, bits);
> +		dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
> +	}
> +}
> +
> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> +			bool enable)
> +{
> +	u8 id;
> +
> +	id = to_vs_display_id(dc, crtc);
> +	dc_hw_enable_gamma(&dc->hw, id, enable);
> +}
> +
> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable)
> +{
> +	dc_hw_enable_interrupt(&dc->hw, enable);
> +}
> +
> +static u32 calc_factor(u32 src, u32 dest)
> +{
> +	u32 factor = 1 << 16;
> +
> +	if (src > 1 && dest > 1)
> +		factor = ((src - 1) << 16) / (dest - 1);
> +
> +	return factor;
> +}
> +
> +static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
> +			 struct dc_hw_scale *scale)
> +{
> +	int dst_w = drm_rect_width(&state->dst);
> +	int dst_h = drm_rect_height(&state->dst);
> +	int src_w, src_h, temp;
> +
> +	scale->enable = false;
> +
> +	if (roi->enable) {
> +		src_w = roi->width;
> +		src_h = roi->height;
> +	} else {
> +		src_w = drm_rect_width(&state->src) >> 16;
> +		src_h = drm_rect_height(&state->src) >> 16;
> +	}
> +
> +	if (drm_rotation_90_or_270(state->rotation)) {
> +		temp = src_w;
> +		src_w = src_h;
> +		src_h = temp;
> +	}
> +
> +	if (src_w != dst_w) {
> +		scale->scale_factor_x = calc_factor(src_w, dst_w);
> +		scale->enable = true;
> +	} else {
> +		scale->scale_factor_x = 1 << 16;
> +	}
> +	if (src_h != dst_h) {
> +		scale->scale_factor_y = calc_factor(src_h, dst_h);
> +		scale->enable = true;
> +	} else {
> +		scale->scale_factor_y = 1 << 16;
> +	}
> +}
> +
> +static void update_fb(struct vs_plane *plane, u8 display_id,
> +		      struct dc_hw_fb *fb, struct drm_plane_state *state)
> +{
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_framebuffer *drm_fb = state->fb;
> +	struct drm_rect *src = &state->src;
> +
> +	fb->display_id = display_id;
> +	fb->y_address = plane_state->dma_addr[0];
> +	fb->y_stride = drm_fb->pitches[0];
> +	if (drm_fb->format->format == DRM_FORMAT_YVU420) {
> +		fb->u_address = plane_state->dma_addr[2];
> +		fb->v_address = plane_state->dma_addr[1];
> +		fb->u_stride = drm_fb->pitches[2];
> +		fb->v_stride = drm_fb->pitches[1];
> +	} else {
> +		fb->u_address = plane_state->dma_addr[1];
> +		fb->v_address = plane_state->dma_addr[2];
> +		fb->u_stride = drm_fb->pitches[1];
> +		fb->v_stride = drm_fb->pitches[2];
> +	}
> +	fb->width = drm_rect_width(src) >> 16;
> +	fb->height = drm_rect_height(src) >> 16;
> +	fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
> +	fb->rotation = to_vs_rotation(state->rotation);
> +	fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
> +	fb->zpos = state->zpos;
> +	fb->enable = state->visible;
> +	update_format(drm_fb->format->format, drm_fb->modifier, fb);
> +	update_swizzle(drm_fb->format->format, fb);
> +	update_watermark(plane_state->watermark, fb);
> +	plane_state->status.tile_mode = fb->tile_mode;
> +}
> +
> +static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
> +			   struct vs_plane_state *plane_state)
> +{
> +	dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
> +	plane_state->degamma_changed = false;
> +}
> +
> +static void update_roi(struct vs_dc *dc, u8 id,
> +		       struct vs_plane_state *plane_state,
> +		       struct dc_hw_roi *roi,
> +		       struct drm_plane_state *state)
> +{
> +	struct drm_vs_roi *data;
> +	struct drm_rect *src = &state->src;
> +	u16 src_w = drm_rect_width(src) >> 16;
> +	u16 src_h = drm_rect_height(src) >> 16;
> +
> +	if (plane_state->roi) {
> +		data = plane_state->roi->data;
> +
> +		if (data->enable) {
> +			roi->x = data->roi_x;
> +			roi->y = data->roi_y;
> +			roi->width = (data->roi_x + data->roi_w > src_w) ?
> +						 (src_w - data->roi_x) : data->roi_w;
> +			roi->height = (data->roi_y + data->roi_h > src_h) ?
> +						  (src_h - data->roi_y) : data->roi_h;
> +			roi->enable = true;
> +		} else {
> +			roi->enable = false;
> +		}
> +
> +		dc_hw_update_roi(&dc->hw, id, roi);
> +	} else {
> +		roi->enable = false;
> +	}
> +}
> +
> +static void update_color_mgmt(struct vs_dc *dc, u8 id,
> +			      struct dc_hw_fb *fb,
> +			      struct vs_plane_state *plane_state)
> +{
> +	struct drm_vs_color_mgmt *data;
> +	struct dc_hw_colorkey colorkey;
> +
> +	if (plane_state->color_mgmt) {
> +		data = plane_state->color_mgmt->data;
> +
> +		fb->clear_enable = data->clear_enable;
> +		fb->clear_value = data->clear_value;
> +
> +		if (data->colorkey > data->colorkey_high)
> +			data->colorkey = data->colorkey_high;
> +
> +		colorkey.colorkey = data->colorkey;
> +		colorkey.colorkey_high = data->colorkey_high;
> +		colorkey.transparency = (data->transparency) ?
> +				DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
> +		dc_hw_update_colorkey(&dc->hw, id, &colorkey);
> +	}
> +}
> +
> +static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			 struct drm_plane *drm_plane,
> +			 struct drm_atomic_state *drm_state)
> +{
> +	struct dc_hw_fb fb = {0};
> +	struct dc_hw_scale scale;
> +	struct dc_hw_position pos;
> +	struct dc_hw_blend blend;
> +	struct dc_hw_roi roi;
> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> +									   drm_plane);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_rect *dest = &state->dst;
> +	bool dec_enable = false;
> +	u8 display_id = 0;
> +
> +	display_id = to_vs_display_id(dc, state->crtc);
> +	update_fb(plane, display_id, &fb, state);
> +	fb.dec_enable = dec_enable;
> +
> +	update_roi(dc, plane->id, plane_state, &roi, state);
> +
> +	update_scale(state, &roi, &scale);
> +
> +	if (plane_state->degamma_changed)
> +		update_degamma(dc, plane, plane_state);
> +
> +	pos.start_x = dest->x1;
> +	pos.start_y = dest->y1;
> +	pos.end_x = dest->x2;
> +	pos.end_y = dest->y2;
> +
> +	blend.alpha = (u8)(state->alpha >> 8);
> +	blend.blend_mode = (u8)(state->pixel_blend_mode);
> +
> +	update_color_mgmt(dc, plane->id, &fb, plane_state);
> +
> +	dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
> +}
> +
> +static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
> +		       struct drm_plane *drm_plane,
> +		       struct drm_atomic_state *drm_state)
> +{
> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> +									   drm_plane);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_vs_watermark *data;
> +	struct dc_hw_qos qos;
> +
> +	if (plane_state->watermark) {
> +		data = plane_state->watermark->data;
> +
> +		if (data->qos_high) {
> +			if (data->qos_low > data->qos_high)
> +				data->qos_low = data->qos_high;
> +
> +			qos.low_value = data->qos_low & 0x0F;
> +			qos.high_value = data->qos_high & 0x0F;
> +			dc_hw_update_qos(&dc->hw, &qos);
> +		}
> +	}
> +}
> +
> +static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
> +{
> +	u8 size_type;
> +
> +	switch (state->crtc_w) {
> +	case 32:
> +		size_type = CURSOR_SIZE_32X32;
> +		break;
> +	case 64:
> +		size_type = CURSOR_SIZE_64X64;
> +		break;
> +	default:
> +		size_type = CURSOR_SIZE_32X32;
> +		break;
> +	}
> +
> +	cursor->size = size_type;
> +}
> +
> +static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> +				struct drm_plane *drm_plane,
> +				struct drm_atomic_state *drm_state)
> +{
> +	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
> +								       drm_plane);
> +	struct vs_plane_state *plane_state = to_vs_plane_state(state);
> +	struct drm_framebuffer *drm_fb = state->fb;
> +	struct dc_hw_cursor cursor;
> +
> +	cursor.address = plane_state->dma_addr[0];
> +	cursor.x = state->crtc_x;
> +	cursor.y = state->crtc_y;
> +	cursor.hot_x = drm_fb->hot_x;
> +	cursor.hot_y = drm_fb->hot_y;
> +	cursor.display_id = to_vs_display_id(dc, state->crtc);
> +	update_cursor_size(state, &cursor);
> +	cursor.enable = true;
> +
> +	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
> +}
> +
> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			struct drm_plane *drm_plane,
> +			struct drm_atomic_state *drm_state)
> +{
> +	update_plane(dc, plane, drm_plane, drm_state);
> +	update_qos(dc, plane, drm_plane, drm_state);
> +}
> +
> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			       struct drm_plane *drm_plane,
> +			       struct drm_atomic_state *drm_state)
> +{
> +	update_cursor_plane(dc, plane, drm_plane, drm_state);
> +}
> +
> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			 struct drm_plane_state *old_state)
> +{
> +	struct dc_hw_fb fb = {0};
> +
> +	fb.enable = false;
> +	dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
> +}
> +
> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> +				struct drm_plane_state *old_state)
> +{
> +	struct dc_hw_cursor cursor = {0};
> +
> +	cursor.enable = false;
> +	cursor.display_id = to_vs_display_id(dc, old_state->crtc);
> +	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
> +}
> +
> +static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
> +				u64 modifier)
> +{
> +	const u64 *mods;
> +
> +	if (!plane_info->modifiers)
> +		return false;
> +
> +	for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
> +		if (*mods == modifier)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
> +		      struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> +										 plane);
> +
> +	struct drm_framebuffer *fb = new_plane_state->fb;
> +	const struct vs_plane_info *plane_info;
> +	struct drm_crtc *crtc = new_plane_state->crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +
> +	plane_info = &dc->hw.info->planes[vs_plane->id];
> +
> +	if (fb->width < plane_info->min_width ||
> +	    fb->width > plane_info->max_width ||
> +	    fb->height < plane_info->min_height ||
> +	    fb->height > plane_info->max_height)
> +		drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
> +			     vs_plane->id);
> +
> +	if (!vs_dc_mod_supported(plane_info, fb->modifier)) {
> +		drm_err(plane->dev, "unsupported modifier on plane%d.\n", vs_plane->id);
> +		return -EINVAL;
> +	}
> +
> +	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
> +	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> +						  plane_info->min_scale,
> +						  plane_info->max_scale,
> +						  true, true);
> +}
> +
> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
> +			     struct drm_atomic_state *state)
> +{
> +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> +									   plane);
> +	struct drm_framebuffer *fb = new_plane_state->fb;
> +	const struct vs_plane_info *plane_info;
> +	struct drm_crtc *crtc = new_plane_state->crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct vs_plane *vs_plane = to_vs_plane(plane);
> +
> +	plane_info = &dc->hw.info->planes[vs_plane->id];
> +
> +	if (fb->width < plane_info->min_width ||
> +	    fb->width > plane_info->max_width ||
> +	    fb->height < plane_info->min_height ||
> +	    fb->height > plane_info->max_height)
> +		drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", vs_plane->id);
> +
> +	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state))
> +		return -EINVAL;
> +
> +	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
> +						plane_info->min_scale,
> +						plane_info->max_scale,
> +						true, true);
> +}
> +
> +static void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
> +{
> +	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
> +
> +	drm_crtc_handle_vblank(crtc);
> +
> +	vs_crtc_state->underflow = underflow;
> +}
> +
> +static irqreturn_t dc_isr(int irq, void *data)
> +{
> +	struct vs_dc *dc = data;
> +	struct vs_dc_info *dc_info = dc->hw.info;
> +	u32 i, ret;
> +
> +	ret = dc_hw_get_interrupt(&dc->hw);
> +
> +	for (i = 0; i < dc_info->panel_num; i++)
> +		vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
> +
> +	return IRQ_HANDLED;
> +}
> +
> +void vs_dc_commit(struct vs_dc *dc)
> +{
> +	dc_hw_enable_shadow_register(&dc->hw, false);
> +
> +	dc_hw_commit(&dc->hw);
> +
> +	if (dc->first_frame)
> +		dc->first_frame = false;
> +
> +	dc_hw_enable_shadow_register(&dc->hw, true);
> +}
> +
> +static int dc_bind(struct device *dev, struct device *master, void *data)
> +{
> +	struct drm_device *drm_dev = data;
> +	struct vs_dc *dc = dev_get_drvdata(dev);
> +	struct device_node *port;
> +	struct vs_crtc *crtc;
> +	struct vs_dc_info *dc_info;
> +	struct vs_plane *plane;
> +	struct vs_plane_info *plane_info;
> +	int i, ret;
> +	u32 ctrc_mask = 0;
> +
> +	if (!drm_dev || !dc) {
> +		dev_err(dev, "devices are not created.\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = dc_init(dev);
> +	if (ret < 0) {
> +		drm_err(drm_dev, "Failed to initialize DC hardware.\n");
> +		return ret;
> +	}
> +
> +	port = of_get_child_by_name(dev->of_node, "port");
> +	if (!port) {
> +		drm_err(drm_dev, "no port node found\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(port);
> +
> +	dc_info = dc->hw.info;
> +
> +	for (i = 0; i < dc_info->panel_num; i++) {
> +		crtc = vs_crtc_create(drm_dev, dc_info);
> +		if (!crtc) {
> +			drm_err(drm_dev, "Failed to create CRTC.\n");
> +			ret = -ENOMEM;
> +			return ret;
> +		}
> +
> +		crtc->base.port = port;
> +		crtc->dev = dev;
> +		dc->crtc[i] = crtc;
> +		ctrc_mask |= drm_crtc_mask(&crtc->base);
> +	}
> +
> +	for (i = 0; i < dc_info->plane_num; i++) {
> +		plane_info = (struct vs_plane_info *)&dc_info->planes[i];
> +
> +		if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
> +						drm_crtc_mask(&dc->crtc[0]->base));
> +		} else if (!strcmp(plane_info->name, "Primary_1") ||
> +				   !strcmp(plane_info->name, "Cursor_1")) {
> +			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
> +						drm_crtc_mask(&dc->crtc[1]->base));

Do you somehow verify that dc->crtc[0] and dc->crtc[1] are not NULL here?

> +		} else {
> +			plane = vs_plane_create(drm_dev, plane_info,
> +						dc_info->layer_num, ctrc_mask);
> +		}

In addition to Maxime's comment, I think it would be easier to read if 
you only set the plane's crtc make in these if-else branches and then 
call vs_plane_create() with the result. Like this

   plane_crtc_mask = crtc_mask;

   if (primary || cursor)
     plane_crtc_mask = drm_crtc_mask(&dc->crtc[0]->base)
   else if (primary_1 || cursor_1)
     plane_crtc_mask = drm_crtc_mask(&dc->crtc[1]->base)

   vs_plane_create(..., plane_crtc_mask)

> +
> +		if (IS_ERR(plane)) {
> +			dev_err(dev, "failed to construct plane\n");
> +			return PTR_ERR(plane);
> +		}
> +
> +		plane->id = i;
> +		dc->planes[i].id = plane_info->id;
> +
> +		if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
> +			if (!strcmp(plane_info->name, "Primary"))
> +				dc->crtc[0]->base.primary = &plane->base;
> +			else
> +				dc->crtc[1]->base.primary = &plane->base;
> +			drm_dev->mode_config.min_width = plane_info->min_width;
> +			drm_dev->mode_config.min_height =
> +							plane_info->min_height;
> +			drm_dev->mode_config.max_width = plane_info->max_width;
> +			drm_dev->mode_config.max_height =
> +							plane_info->max_height;
> +		}

If you have multiple primary planes, the later planes overwrite the 
settings from the earlier ones. Is that intentional?

> +
> +		if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
> +			if (!strcmp(plane_info->name, "Cursor"))
> +				dc->crtc[0]->base.cursor = &plane->base;
> +			else
> +				dc->crtc[1]->base.cursor = &plane->base;
> +			drm_dev->mode_config.cursor_width =
> +							plane_info->max_width;
> +			drm_dev->mode_config.cursor_height =
> +							plane_info->max_height;
> +		}

Same question about overwriting as for the primary planes?

> +	}
> +
> +	vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
> +	return 0;
> +}
> +
> +static void dc_unbind(struct device *dev, struct device *master, void *data)
> +{
> +	dc_deinit(dev);
> +}
> +
> +const struct component_ops dc_component_ops = {
> +	.bind = dc_bind,
> +	.unbind = dc_unbind,
> +};
> +
> +static const struct of_device_id dc_driver_dt_match[] = {
> +	{ .compatible = "starfive,jh7110-dc8200", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
> +
> +static int dc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct vs_dc *dc;
> +	int irq, ret, i;
> +
> +	dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
> +	if (!dc)
> +		return -ENOMEM;
> +
> +	dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(dc->hw.hi_base))
> +		return PTR_ERR(dc->hw.hi_base);
> +
> +	dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
> +	if (IS_ERR(dc->hw.reg_base))
> +		return PTR_ERR(dc->hw.reg_base);
> +
> +	dc->nclks = ARRAY_SIZE(dc->clk_vout);
> +	for (i = 0; i < dc->nclks; ++i)
> +		dc->clk_vout[i].id = vout_clocks[i];
> +	ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
> +	if (ret) {
> +		dev_err(dev, "Failed to get clk controls\n");
> +		return ret;
> +	}
> +
> +	dc->nrsts = ARRAY_SIZE(dc->rst_vout);
> +	for (i = 0; i < dc->nrsts; ++i)
> +		dc->rst_vout[i].id = vout_resets[i];
> +	ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
> +						 dc->rst_vout);
> +	if (ret) {
> +		dev_err(dev, "Failed to get reset controls\n");
> +		return ret;
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +
> +	ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to install irq:%u.\n", irq);
> +		return ret;
> +	}
> +
> +	dev_set_drvdata(dev, dc);
> +
> +	return component_add(dev, &dc_component_ops);
> +}
> +
> +static int dc_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	component_del(dev, &dc_component_ops);
> +
> +	dev_set_drvdata(dev, NULL);
> +
> +	return 0;
> +}
> +
> +struct platform_driver dc_platform_driver = {
> +	.probe = dc_probe,
> +	.remove = dc_remove,
> +	.driver = {
> +		.name = "vs-dc",
> +		.of_match_table = of_match_ptr(dc_driver_dt_match),
> +	},
> +};
> +
> +MODULE_AUTHOR("StarFive Corporation");
> +MODULE_DESCRIPTION("VeriSilicon DC Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
> new file mode 100644
> index 000000000..8e96fd32c
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#ifndef __VS_DC_H__
> +#define __VS_DC_H__
> +
> +#include <linux/clk.h>
> +#include <linux/mm_types.h>
> +#include <linux/reset.h>
> +
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_modes.h>
> +
> +#include "vs_crtc.h"
> +#include "vs_dc_hw.h"
> +#include "vs_plane.h"
> +
> +struct vs_dc_plane {
> +	enum dc_hw_plane_id id;
> +};
> +
> +enum vout_clk {
> +	CLK_VOUT_NOC_DISP = 0,
> +	CLK_VOUT_PIX0,
> +	CLK_VOUT_PIX1,
> +	CLK_VOUT_CORE,
> +	CLK_VOUT_AXI,
> +	CLK_VOUT_AHB,
> +	CLK_VOUT_HDMI_PIX,
> +	CLK_VOUT_SOC_PIX,
> +	CLK_VOUT_NUM
> +};
> +
> +enum rst_vout {
> +	RST_VOUT_AXI = 0,
> +	RST_VOUT_AHB,
> +	RST_VOUT_CORE,
> +	RST_VOUT_NUM
> +};
> +
> +struct vs_dc {
> +	struct vs_crtc		*crtc[DC_DISPLAY_NUM];
> +	struct dc_hw		hw;
> +	bool			first_frame;
> +
> +	struct vs_dc_plane	planes[PLANE_NUM];
> +	struct clk_bulk_data	clk_vout[CLK_VOUT_NUM];
> +	int			nclks;
> +	struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
> +	int			nrsts;
> +};
> +
> +void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc);
> +void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc);
> +
> +void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
> +		     struct drm_color_lut *lut, unsigned int size);
> +void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc, bool enable);
> +void vs_dc_enable_vblank(struct vs_dc *dc, bool enable);
> +void vs_dc_commit(struct vs_dc *dc);
> +void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			struct drm_plane *drm_plane,
> +			struct drm_atomic_state *drm_state);
> +void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			 struct drm_plane_state *old_state);
> +int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
> +		      struct drm_atomic_state *state);
> +void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> +			       struct drm_plane *drm_plane,
> +			       struct drm_atomic_state *drm_state);
> +void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
> +				struct drm_plane_state *old_state);
> +int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
> +			     struct drm_atomic_state *state);
> +
> +extern struct platform_driver dc_platform_driver;
> +
> +#endif /* __VS_DC_H__ */
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> new file mode 100644
> index 000000000..e5acb7eb4
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
> @@ -0,0 +1,1959 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/io.h>
> +#include <linux/media-bus-format.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_blend.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/vs_drm.h>
> +
> +#include "vs_dc_hw.h"
> +#include "vs_type.h"
> +
> +static const u32 horkernel[] = {
> +	0x00000000, 0x20000000, 0x00002000, 0x00000000,
> +	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> +	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> +	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> +	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> +	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> +	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> +	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> +	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> +	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> +	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> +	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> +	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> +	0x00000000, 0x00000000, 0x00000000, 0x01470000,
> +	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> +	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> +	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> +	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> +	0x00000000, 0x00000000, 0x00004000, 0x00000000,
> +	0x00000000, 0x00000000, 0x20002000, 0x00000000,
> +	0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
> +	0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
> +	0x00000000, 0x00000000, 0x00000000, 0x14680000,
> +	0x00002b98, 0x00000000, 0x00000000, 0x00000000,
> +	0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
> +	0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
> +	0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
> +	0x00000000, 0x087f0000, 0x00003781, 0x00000000,
> +	0x00000000, 0x00000000, 0x399a0666, 0x00000000,
> +	0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
> +	0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
> +	0x00000000, 0x00000000, 0x00000000, 0x021f0000,
> +};
> +
> +#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))

Either drop this in favor of the regular ARRAY_SIZE() macro, or hardcode 
the size if it's a fixed hardware setting.

> +
> +static const u32 verkernel[] = {
> +	0x00000000, 0x20000000, 0x00002000, 0x00000000,
> +	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
> +	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
> +	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
> +	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
> +	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
> +	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
> +	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
> +	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
> +	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
> +	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
> +	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
> +	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
> +	0x00000000, 0x00000000, 0x00000000, 0x01470000,
> +	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
> +	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
> +	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
> +	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
> +	0x00000000, 0x00000000, 0x00004000, 0x00000000,
> +	0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
> +	0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
> +	0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
> +};
> +
> +#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))

Same as H_COEF_SIZE;

> +
> +/*
> + * RGB 709->2020 conversion parameters
> + */
> +static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {

'static const' here and for the arrays below.

> +	10279,	5395,	709,
> +	1132,	15065,	187,
> +	269,	1442,	14674
> +};
> +
> +/*
> + * YUV601 to RGB conversion parameters
> + * YUV2RGB[0]  - [8] : C0 - C8;
> + * YUV2RGB[9]  - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> +	1196,	0,			1640,	1196,
> +	-404,	-836,		1196,	2076,
> +	0,		-916224,	558336,	-1202944,
> +	64,		 940,		64,		960

Might be my email reader, but indention looks off here.

> +};
> +
> +/*
> + * YUV709 to RGB conversion parameters
> + * YUV2RGB[0]  - [8] : C0 - C8;
> + * YUV2RGB[9]  - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> +	1196,		0,		1844,	1196,
> +	-220,		-548,	1196,	2172,
> +	0,			-1020672, 316672,  -1188608,
> +	64,			940,		64,		960

Indention?

> +};
> +
> +/*
> + * YUV2020 to RGB conversion parameters
> + * YUV2RGB[0]  - [8] : C0 - C8;
> + * YUV2RGB[9]  - [11]: D0 - D2;
> + * YUV2RGB[12] - [13]: Y clamp min & max calue;
> + * YUV2RGB[14] - [15]: UV clamp min & max calue;
> + */
> +static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
> +	1196, 0, 1724, 1196,
> +	-192, -668, 1196, 2200,
> +	0, -959232, 363776, -1202944,
> +	64, 940, 64, 960

Indention.

> +};
> +
> +/*
> + * RGB to YUV2020 conversion parameters
> + * RGB2YUV[0] - [8] : C0 - C8;
> + * RGB2YUV[9] - [11]: D0 - D2;
> + */
> +static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
> +	230,	594,	52,
> +	-125,  -323,	448,
> +	448,   -412,   -36,
> +	64,		512,	512
> +};
> +
> +/*
> + * Degamma table for 709 color space data.
> + */
> +static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
> +	0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
> +	0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
> +	0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
> +	0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
> +	0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
> +	0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
> +	0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
> +	0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
> +	0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
> +	0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
> +	0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
> +	0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
> +	0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
> +	0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
> +	0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
> +	0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
> +	0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
> +	0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
> +	0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
> +	0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
> +	0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
> +	0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
> +	0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
> +	0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
> +	0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
> +	0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
> +	0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
> +	0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
> +	0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
> +	0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
> +	0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
> +	0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
> +};
> +
> +/*
> + * Degamma table for 2020 color space data.
> + */
> +static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> +	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
> +	0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
> +	0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
> +	0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
> +	0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
> +	0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
> +	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
> +	0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
> +	0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
> +	0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
> +	0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
> +	0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
> +	0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
> +	0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
> +	0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
> +	0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
> +	0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
> +	0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
> +	0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
> +	0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
> +	0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
> +	0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
> +	0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
> +	0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
> +	0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
> +	0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
> +	0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
> +	0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
> +	0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
> +	0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
> +	0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
> +};
> +
> +/* one is for primary plane and the other is for all overlay planes */
> +static const struct dc_hw_plane_reg dc_plane_reg[] = {
> +	{
> +	.y_address		= DC_FRAMEBUFFER_ADDRESS,
> +	.u_address		= DC_FRAMEBUFFER_U_ADDRESS,
> +	.v_address		= DC_FRAMEBUFFER_V_ADDRESS,
> +	.y_stride		= DC_FRAMEBUFFER_STRIDE,
> +	.u_stride		= DC_FRAMEBUFFER_U_STRIDE,
> +	.v_stride		= DC_FRAMEBUFFER_V_STRIDE,
> +	.size			= DC_FRAMEBUFFER_SIZE,
> +	.top_left		= DC_FRAMEBUFFER_TOP_LEFT,
> +	.bottom_right	= DC_FRAMEBUFFER_BOTTOM_RIGHT,
> +	.scale_factor_x			= DC_FRAMEBUFFER_SCALE_FACTOR_X,
> +	.scale_factor_y			= DC_FRAMEBUFFER_SCALE_FACTOR_Y,
> +	.h_filter_coef_index	= DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
> +	.h_filter_coef_data		= DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
> +	.v_filter_coef_index	= DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
> +	.v_filter_coef_data		= DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
> +	.init_offset			= DC_FRAMEBUFFER_INIT_OFFSET,
> +	.color_key				= DC_FRAMEBUFFER_COLOR_KEY,
> +	.color_key_high			= DC_FRAMEBUFFER_COLOR_KEY_HIGH,
> +	.clear_value			= DC_FRAMEBUFFER_CLEAR_VALUE,
> +	.color_table_index		= DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
> +	.color_table_data		= DC_FRAMEBUFFER_COLOR_TABLE_DATA,
> +	.scale_config			= DC_FRAMEBUFFER_SCALE_CONFIG,
> +	.water_mark				= DC_FRAMEBUFFER_WATER_MARK,
> +	.degamma_index			= DC_FRAMEBUFFER_DEGAMMA_INDEX,
> +	.degamma_data			= DC_FRAMEBUFFER_DEGAMMA_DATA,
> +	.degamma_ex_data		= DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
> +	.src_global_color		= DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
> +	.dst_global_color		= DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
> +	.blend_config			= DC_FRAMEBUFFER_BLEND_CONFIG,
> +	.roi_origin				= DC_FRAMEBUFFER_ROI_ORIGIN,
> +	.roi_size				= DC_FRAMEBUFFER_ROI_SIZE,
> +	.yuv_to_rgb_coef0			= DC_FRAMEBUFFER_YUVTORGB_COEF0,
> +	.yuv_to_rgb_coef1			= DC_FRAMEBUFFER_YUVTORGB_COEF1,
> +	.yuv_to_rgb_coef2			= DC_FRAMEBUFFER_YUVTORGB_COEF2,
> +	.yuv_to_rgb_coef3			= DC_FRAMEBUFFER_YUVTORGB_COEF3,
> +	.yuv_to_rgb_coef4			= DC_FRAMEBUFFER_YUVTORGB_COEF4,
> +	.yuv_to_rgb_coefd0			= DC_FRAMEBUFFER_YUVTORGB_COEFD0,
> +	.yuv_to_rgb_coefd1			= DC_FRAMEBUFFER_YUVTORGB_COEFD1,
> +	.yuv_to_rgb_coefd2			= DC_FRAMEBUFFER_YUVTORGB_COEFD2,
> +	.y_clamp_bound				= DC_FRAMEBUFFER_Y_CLAMP_BOUND,
> +	.uv_clamp_bound				= DC_FRAMEBUFFER_UV_CLAMP_BOUND,
> +	.rgb_to_rgb_coef0			= DC_FRAMEBUFFER_RGBTORGB_COEF0,
> +	.rgb_to_rgb_coef1			= DC_FRAMEBUFFER_RGBTORGB_COEF1,
> +	.rgb_to_rgb_coef2			= DC_FRAMEBUFFER_RGBTORGB_COEF2,
> +	.rgb_to_rgb_coef3			= DC_FRAMEBUFFER_RGBTORGB_COEF3,
> +	.rgb_to_rgb_coef4			= DC_FRAMEBUFFER_RGBTORGB_COEF4,
> +	},
> +	{
> +	.y_address		= DC_OVERLAY_ADDRESS,
> +	.u_address		= DC_OVERLAY_U_ADDRESS,
> +	.v_address		= DC_OVERLAY_V_ADDRESS,
> +	.y_stride		= DC_OVERLAY_STRIDE,
> +	.u_stride		= DC_OVERLAY_U_STRIDE,
> +	.v_stride		= DC_OVERLAY_V_STRIDE,
> +	.size			= DC_OVERLAY_SIZE,
> +	.top_left		= DC_OVERLAY_TOP_LEFT,
> +	.bottom_right	= DC_OVERLAY_BOTTOM_RIGHT,
> +	.scale_factor_x	= DC_OVERLAY_SCALE_FACTOR_X,
> +	.scale_factor_y	= DC_OVERLAY_SCALE_FACTOR_Y,
> +	.h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
> +	.h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
> +	.v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
> +	.v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
> +	.init_offset		 = DC_OVERLAY_INIT_OFFSET,
> +	.color_key			 = DC_OVERLAY_COLOR_KEY,
> +	.color_key_high			= DC_OVERLAY_COLOR_KEY_HIGH,
> +	.clear_value		 = DC_OVERLAY_CLEAR_VALUE,
> +	.color_table_index	 = DC_OVERLAY_COLOR_TABLE_INDEX,
> +	.color_table_data	 = DC_OVERLAY_COLOR_TABLE_DATA,
> +	.scale_config		 = DC_OVERLAY_SCALE_CONFIG,
> +	.water_mark				= DC_OVERLAY_WATER_MARK,
> +	.degamma_index		 = DC_OVERLAY_DEGAMMA_INDEX,
> +	.degamma_data		 = DC_OVERLAY_DEGAMMA_DATA,
> +	.degamma_ex_data	 = DC_OVERLAY_DEGAMMA_EX_DATA,
> +	.src_global_color	 = DC_OVERLAY_SRC_GLOBAL_COLOR,
> +	.dst_global_color	 = DC_OVERLAY_DST_GLOBAL_COLOR,
> +	.blend_config		 = DC_OVERLAY_BLEND_CONFIG,
> +	.roi_origin				= DC_OVERLAY_ROI_ORIGIN,
> +	.roi_size				= DC_OVERLAY_ROI_SIZE,
> +	.yuv_to_rgb_coef0		 = DC_OVERLAY_YUVTORGB_COEF0,
> +	.yuv_to_rgb_coef1		 = DC_OVERLAY_YUVTORGB_COEF1,
> +	.yuv_to_rgb_coef2		 = DC_OVERLAY_YUVTORGB_COEF2,
> +	.yuv_to_rgb_coef3		 = DC_OVERLAY_YUVTORGB_COEF3,
> +	.yuv_to_rgb_coef4			= DC_OVERLAY_YUVTORGB_COEF4,
> +	.yuv_to_rgb_coefd0			= DC_OVERLAY_YUVTORGB_COEFD0,
> +	.yuv_to_rgb_coefd1			= DC_OVERLAY_YUVTORGB_COEFD1,
> +	.yuv_to_rgb_coefd2			= DC_OVERLAY_YUVTORGB_COEFD2,
> +	.y_clamp_bound		 = DC_OVERLAY_Y_CLAMP_BOUND,
> +	.uv_clamp_bound		 = DC_OVERLAY_UV_CLAMP_BOUND,
> +	.rgb_to_rgb_coef0		 = DC_OVERLAY_RGBTORGB_COEF0,
> +	.rgb_to_rgb_coef1		 = DC_OVERLAY_RGBTORGB_COEF1,
> +	.rgb_to_rgb_coef2		 = DC_OVERLAY_RGBTORGB_COEF2,
> +	.rgb_to_rgb_coef3		 = DC_OVERLAY_RGBTORGB_COEF3,
> +	.rgb_to_rgb_coef4		 = DC_OVERLAY_RGBTORGB_COEF4,
> +	},
> +};
> +
> +static const u32 primary_overlay_format0[] = {

These format arrays are supposed to be roughly sorted by hardware 
preference. This gives user-space programs an idea of what the hardware 
wants. Are these 4444 and 1555 formats really preferable over their 8888 
and 2101010 variants?

> +	DRM_FORMAT_XRGB4444,
> +	DRM_FORMAT_XBGR4444,
> +	DRM_FORMAT_RGBX4444,
> +	DRM_FORMAT_BGRX4444,
> +	DRM_FORMAT_ARGB4444,
> +	DRM_FORMAT_ABGR4444,
> +	DRM_FORMAT_RGBA4444,
> +	DRM_FORMAT_BGRA4444,
> +	DRM_FORMAT_XRGB1555,
> +	DRM_FORMAT_XBGR1555,
> +	DRM_FORMAT_RGBX5551,
> +	DRM_FORMAT_BGRX5551,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_ABGR1555,
> +	DRM_FORMAT_RGBA5551,
> +	DRM_FORMAT_BGRA5551,
> +	DRM_FORMAT_RGB565,
> +	DRM_FORMAT_BGR565,
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_RGBX8888,
> +	DRM_FORMAT_BGRX8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_RGBA8888,
> +	DRM_FORMAT_BGRA8888,
> +	DRM_FORMAT_ARGB2101010,
> +	DRM_FORMAT_ABGR2101010,
> +	DRM_FORMAT_RGBA1010102,
> +	DRM_FORMAT_BGRA1010102,
> +	DRM_FORMAT_YUYV,
> +	DRM_FORMAT_YVYU,
> +	DRM_FORMAT_UYVY,
> +	DRM_FORMAT_VYUY,
> +	DRM_FORMAT_YVU420,
> +	DRM_FORMAT_YUV420,
> +	DRM_FORMAT_NV12,
> +	DRM_FORMAT_NV21,
> +	DRM_FORMAT_NV16,
> +	DRM_FORMAT_NV61,
> +	DRM_FORMAT_P010,
> +};
> +
> +static const u32 primary_overlay_format1[] = {
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_RGBX8888,
> +	DRM_FORMAT_BGRX8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_RGBA8888,
> +	DRM_FORMAT_BGRA8888,
> +	DRM_FORMAT_ARGB2101010,
> +	DRM_FORMAT_ABGR2101010,
> +	DRM_FORMAT_RGBA1010102,
> +	DRM_FORMAT_BGRA1010102,
> +	DRM_FORMAT_NV12,
> +	DRM_FORMAT_NV21,
> +	DRM_FORMAT_YUV444,
> +};
> +
> +static const u32 cursor_formats[] = {
> +	DRM_FORMAT_ARGB8888
> +};
> +
> +static const u64 format_modifier0[] = {
> +	DRM_FORMAT_MOD_LINEAR,
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X8),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_8X8),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X8),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X4),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X4),
> +	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_4X8),
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +static const u64 secondary_format_modifiers[] = {
> +	DRM_FORMAT_MOD_LINEAR,
> +	DRM_FORMAT_MOD_INVALID
> +};
> +
> +#define FRAC_16_16(mult, div)	 (((mult) << 16) / (div))
> +
> +static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {

Please double-check the indention in this array.

Best regards
Thomas
diff mbox series

Patch

diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile
index 7d3be305b..1d48016ca 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -1,7 +1,11 @@ 
 # SPDX-License-Identifier: GPL-2.0
 
-vs_drm-objs := vs_drv.o \
-		vs_modeset.o 
+vs_drm-objs := vs_dc_hw.o \
+		vs_dc.o \
+		vs_crtc.o \
+		vs_drv.o \
+		vs_modeset.o \
+		vs_plane.o
 
 obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o
 
diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c
new file mode 100644
index 000000000..8a658ea77
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_crtc.c
@@ -0,0 +1,257 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/media-bus-format.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/vs_drm.h>
+
+#include "vs_crtc.h"
+#include "vs_dc.h"
+#include "vs_drv.h"
+
+static void vs_crtc_reset(struct drm_crtc *crtc)
+{
+	struct vs_crtc_state *state;
+
+	if (crtc->state) {
+		__drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+		state = to_vs_crtc_state(crtc->state);
+		kfree(state);
+		crtc->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	__drm_atomic_helper_crtc_reset(crtc, &state->base);
+}
+
+static struct drm_crtc_state *
+vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+	struct vs_crtc_state *ori_state;
+	struct vs_crtc_state *state;
+
+	if (!crtc->state)
+		return NULL;
+
+	ori_state = to_vs_crtc_state(crtc->state);
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+	state->output_fmt = ori_state->output_fmt;
+	state->encoder_type = ori_state->encoder_type;
+	state->bpp = ori_state->bpp;
+	state->underflow = ori_state->underflow;
+
+	return &state->base;
+}
+
+static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state)
+{
+	__drm_atomic_helper_crtc_destroy_state(state);
+	kfree(to_vs_crtc_state(state));
+}
+
+static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	vs_dc_enable_vblank(dc, true);
+
+	return 0;
+}
+
+static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	vs_dc_enable_vblank(dc, false);
+}
+
+static const struct drm_crtc_funcs vs_crtc_funcs = {
+	.set_config		= drm_atomic_helper_set_config,
+	.page_flip		= drm_atomic_helper_page_flip,
+	.reset			= vs_crtc_reset,
+	.atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
+	.atomic_destroy_state	= vs_crtc_atomic_destroy_state,
+	.enable_vblank		= vs_crtc_enable_vblank,
+	.disable_vblank		= vs_crtc_disable_vblank,
+};
+
+static u8 cal_pixel_bits(u32 bus_format)
+{
+	u8 bpp;
+
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		bpp = 16;
+		break;
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+		bpp = 18;
+		break;
+	case MEDIA_BUS_FMT_UYVY10_1X20:
+		bpp = 20;
+		break;
+	case MEDIA_BUS_FMT_BGR888_1X24:
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_YUV8_1X24:
+		bpp = 24;
+		break;
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+		bpp = 30;
+		break;
+	default:
+		bpp = 24;
+		break;
+	}
+
+	return bpp;
+}
+
+static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
+				  struct drm_atomic_state *state)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
+
+	vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
+
+	vs_dc_enable(dc, crtc);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
+				   struct drm_atomic_state *state)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	drm_crtc_vblank_off(crtc);
+
+	vs_dc_disable(dc, crtc);
+
+	if (crtc->state->event && !crtc->state->active) {
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+
+		crtc->state->event = NULL;
+	}
+}
+
+static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+									  crtc);
+
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct device *dev = vs_crtc->dev;
+	struct drm_property_blob *blob = crtc->state->gamma_lut;
+	struct drm_color_lut *lut;
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	if (crtc_state->color_mgmt_changed) {
+		if (blob && blob->length) {
+			lut = blob->data;
+			vs_dc_set_gamma(dc, crtc, lut,
+					blob->length / sizeof(*lut));
+			vs_dc_enable_gamma(dc, crtc, true);
+		} else {
+			vs_dc_enable_gamma(dc, crtc, false);
+		}
+	}
+}
+
+static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
+				 struct drm_atomic_state *state)
+{
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct drm_pending_vblank_event *event = crtc->state->event;
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	vs_dc_commit(dc);
+
+	if (event) {
+		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_arm_vblank_event(crtc, event);
+		spin_unlock_irq(&crtc->dev->event_lock);
+		crtc->state->event = NULL;
+	}
+}
+
+static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
+	.atomic_check = drm_crtc_helper_atomic_check,
+	.atomic_enable	= vs_crtc_atomic_enable,
+	.atomic_disable = vs_crtc_atomic_disable,
+	.atomic_begin	= vs_crtc_atomic_begin,
+	.atomic_flush	= vs_crtc_atomic_flush,
+};
+
+static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
+	{ VS_SINGLE_DC,				"single dc mode" },
+	{ VS_MULTI_DC_PRIMARY,		"primary dc for multi dc mode" },
+	{ VS_MULTI_DC_SECONDARY,	"secondary dc for multi dc mode" },
+};
+
+struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
+			       struct vs_dc_info *info)
+{
+	struct vs_crtc *crtc;
+	int ret;
+
+	if (!info)
+		return NULL;
+
+	crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL);
+	if (!crtc)
+		return NULL;
+
+	ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base,
+					 NULL, NULL, &vs_crtc_funcs,
+					 info->name ? info->name : NULL);
+	if (ret)
+		return NULL;
+
+	drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
+
+	if (info->gamma_size) {
+		ret = drm_mode_crtc_set_gamma_size(&crtc->base,
+						   info->gamma_size);
+		if (ret)
+			return NULL;
+
+		drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
+					   info->gamma_size);
+	}
+
+	crtc->max_bpc = info->max_bpc;
+	crtc->color_formats = info->color_formats;
+	return crtc;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.h b/drivers/gpu/drm/verisilicon/vs_crtc.h
new file mode 100644
index 000000000..526dd63e5
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_crtc.h
@@ -0,0 +1,43 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_CRTC_H__
+#define __VS_CRTC_H__
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "vs_type.h"
+
+struct vs_crtc_state {
+	struct drm_crtc_state base;
+
+	u32 output_fmt;
+	u8 encoder_type;
+	u8 bpp;
+	bool underflow;
+};
+
+struct vs_crtc {
+	struct drm_crtc base;
+	struct device *dev;
+	unsigned int max_bpc;
+	unsigned int color_formats;
+};
+
+struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
+			       struct vs_dc_info *info);
+
+static inline struct vs_crtc *to_vs_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct vs_crtc, base);
+}
+
+static inline struct vs_crtc_state *
+to_vs_crtc_state(struct drm_crtc_state *state)
+{
+	return container_of(state, struct vs_crtc_state, base);
+}
+#endif /* __VS_CRTC_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
new file mode 100644
index 000000000..b5ab92d98
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc.c
@@ -0,0 +1,1002 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/component.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_vblank.h>
+#include <drm/vs_drm.h>
+
+#include "vs_dc_hw.h"
+#include "vs_dc.h"
+#include "vs_drv.h"
+
+static const char * const vout_clocks[] = {
+	"noc_bus",
+	"channel0",
+	"channel1",
+	"dc_core",
+	"axi_core",
+	"ahb",
+	"hdmi_tx",
+	"dc_parent",
+
+};
+
+static const char * const vout_resets[] = {
+	"axi",
+	"ahb",
+	"core",
+};
+
+static inline void update_format(u32 format, u64 mod, struct dc_hw_fb *fb)
+{
+	u8 f = FORMAT_A8R8G8B8;
+
+	switch (format) {
+	case DRM_FORMAT_XRGB4444:
+	case DRM_FORMAT_RGBX4444:
+	case DRM_FORMAT_XBGR4444:
+	case DRM_FORMAT_BGRX4444:
+		f = FORMAT_X4R4G4B4;
+		break;
+	case DRM_FORMAT_ARGB4444:
+	case DRM_FORMAT_RGBA4444:
+	case DRM_FORMAT_ABGR4444:
+	case DRM_FORMAT_BGRA4444:
+		f = FORMAT_A4R4G4B4;
+		break;
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_RGBX5551:
+	case DRM_FORMAT_XBGR1555:
+	case DRM_FORMAT_BGRX5551:
+		f = FORMAT_X1R5G5B5;
+		break;
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_RGBA5551:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_BGRA5551:
+		f = FORMAT_A1R5G5B5;
+		break;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		f = FORMAT_R5G6B5;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_BGRX8888:
+		f = FORMAT_X8R8G8B8;
+		break;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_BGRA8888:
+		f = FORMAT_A8R8G8B8;
+		break;
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		f = FORMAT_YUY2;
+		break;
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+		f = FORMAT_UYVY;
+		break;
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+		f = FORMAT_YV12;
+		break;
+	case DRM_FORMAT_NV21:
+		f = FORMAT_NV12;
+		break;
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+		f = FORMAT_NV16;
+		break;
+	case DRM_FORMAT_P010:
+		f = FORMAT_P010;
+		break;
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_RGBA1010102:
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_BGRA1010102:
+		f = FORMAT_A2R10G10B10;
+		break;
+	case DRM_FORMAT_NV12:
+		f = FORMAT_NV12;
+		break;
+	case DRM_FORMAT_YUV444:
+		f = FORMAT_YUV444;
+		break;
+	default:
+		break;
+	}
+
+	fb->format = f;
+}
+
+static inline void update_swizzle(u32 format, struct dc_hw_fb *fb)
+{
+	fb->swizzle = SWIZZLE_ARGB;
+	fb->uv_swizzle = 0;
+
+	switch (format) {
+	case DRM_FORMAT_RGBX4444:
+	case DRM_FORMAT_RGBA4444:
+	case DRM_FORMAT_RGBX5551:
+	case DRM_FORMAT_RGBA5551:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBA1010102:
+		fb->swizzle = SWIZZLE_RGBA;
+		break;
+	case DRM_FORMAT_XBGR4444:
+	case DRM_FORMAT_ABGR4444:
+	case DRM_FORMAT_XBGR1555:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_ABGR2101010:
+		fb->swizzle = SWIZZLE_ABGR;
+		break;
+	case DRM_FORMAT_BGRX4444:
+	case DRM_FORMAT_BGRA4444:
+	case DRM_FORMAT_BGRX5551:
+	case DRM_FORMAT_BGRA5551:
+	case DRM_FORMAT_BGRX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRA1010102:
+		fb->swizzle = SWIZZLE_BGRA;
+		break;
+	case DRM_FORMAT_YVYU:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV61:
+		fb->uv_swizzle = 1;
+		break;
+	default:
+		break;
+	}
+}
+
+static inline void update_watermark(struct drm_property_blob *watermark,
+				    struct dc_hw_fb *fb)
+{
+	struct drm_vs_watermark *data;
+
+	fb->water_mark = 0;
+
+	if (watermark) {
+		data = watermark->data;
+		fb->water_mark = data->watermark & 0xFFFFF;
+	}
+}
+
+static inline u8 to_vs_rotation(unsigned int rotation)
+{
+	u8 rot;
+
+	switch (rotation & DRM_MODE_REFLECT_MASK) {
+	case DRM_MODE_REFLECT_X:
+		rot = FLIP_X;
+		return rot;
+	case DRM_MODE_REFLECT_Y:
+		rot = FLIP_Y;
+		return rot;
+	case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y:
+		rot = FLIP_XY;
+		return rot;
+	default:
+		break;
+	}
+
+	switch (rotation & DRM_MODE_ROTATE_MASK) {
+	case DRM_MODE_ROTATE_0:
+		rot = ROT_0;
+		break;
+	case DRM_MODE_ROTATE_90:
+		rot = ROT_90;
+		break;
+	case DRM_MODE_ROTATE_180:
+		rot = ROT_180;
+		break;
+	case DRM_MODE_ROTATE_270:
+		rot = ROT_270;
+		break;
+	default:
+		rot = ROT_0;
+		break;
+	}
+
+	return rot;
+}
+
+static inline u8 to_vs_yuv_color_space(u32 color_space)
+{
+	u8 cs;
+
+	switch (color_space) {
+	case DRM_COLOR_YCBCR_BT601:
+		cs = COLOR_SPACE_601;
+		break;
+	case DRM_COLOR_YCBCR_BT709:
+		cs = COLOR_SPACE_709;
+		break;
+	case DRM_COLOR_YCBCR_BT2020:
+		cs = COLOR_SPACE_2020;
+		break;
+	default:
+		cs = COLOR_SPACE_601;
+		break;
+	}
+
+	return cs;
+}
+
+static inline u8 to_vs_tile_mode(u64 modifier)
+{
+	if (modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
+		return DC_TILE_MODE4X4;
+
+	return (u8)(modifier & DRM_FORMAT_MOD_VERISILICON_NORM_MODE_MASK);
+}
+
+static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc)
+{
+	u8 panel_num = dc->hw.info->panel_num;
+	u32 index = drm_crtc_index(crtc);
+	int i;
+
+	for (i = 0; i < panel_num; i++) {
+		if (index == dc->crtc[i]->base.index)
+			return i;
+	}
+
+	return 0;
+}
+
+static void vs_drm_update_pitch_alignment(struct drm_device *drm_dev,
+					  unsigned int alignment)
+{
+	struct vs_drm_device *priv = to_vs_drm_private(drm_dev);
+
+	if (alignment > priv->pitch_alignment)
+		priv->pitch_alignment = alignment;
+}
+
+static int plda_clk_rst_init(struct device *dev)
+{
+	int ret = 0;
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	ret = clk_bulk_prepare_enable(dc->nclks, dc->clk_vout);
+	if (ret) {
+		dev_err(dev, "failed to enable clocks\n");
+		return ret;
+	}
+
+	ret = reset_control_bulk_deassert(dc->nrsts, dc->rst_vout);
+	return ret;
+}
+
+static void plda_clk_rst_deinit(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	reset_control_bulk_assert(dc->nrsts, dc->rst_vout);
+	clk_bulk_disable_unprepare(dc->nclks, dc->clk_vout);
+}
+
+static void dc_deinit(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+
+	dc_hw_enable_interrupt(&dc->hw, 0);
+	dc_hw_deinit(&dc->hw);
+	plda_clk_rst_deinit(dev);
+}
+
+static int dc_init(struct device *dev)
+{
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	int ret;
+
+	dc->first_frame = true;
+
+	ret = plda_clk_rst_init(dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to init dc clk reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = dc_hw_init(&dc->hw);
+	if (ret) {
+		dev_err(dev, "failed to init DC HW\n");
+		return ret;
+	}
+	return 0;
+}
+
+void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc)
+{
+	struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct dc_hw_display display;
+
+	display.bus_format = crtc_state->output_fmt;
+	display.h_active = mode->hdisplay;
+	display.h_total = mode->htotal;
+	display.h_sync_start = mode->hsync_start;
+	display.h_sync_end = mode->hsync_end;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		display.h_sync_polarity = true;
+	else
+		display.h_sync_polarity = false;
+
+	display.v_active = mode->vdisplay;
+	display.v_total = mode->vtotal;
+	display.v_sync_start = mode->vsync_start;
+	display.v_sync_end = mode->vsync_end;
+
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		display.v_sync_polarity = true;
+	else
+		display.v_sync_polarity = false;
+
+	display.id = to_vs_display_id(dc, crtc);
+
+	display.enable = true;
+
+	if (crtc_state->encoder_type == DRM_MODE_ENCODER_DSI) {
+		dc_hw_set_out(&dc->hw, OUT_DPI, display.id);
+		clk_set_rate(dc->clk_vout[CLK_VOUT_SOC_PIX].clk, mode->clock * 1000);
+		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX1].clk,
+			       dc->clk_vout[CLK_VOUT_SOC_PIX].clk);
+	} else {
+		dc_hw_set_out(&dc->hw, OUT_DP, display.id);
+		clk_set_parent(dc->clk_vout[CLK_VOUT_PIX0].clk,
+			       dc->clk_vout[CLK_VOUT_HDMI_PIX].clk);
+	}
+
+	dc_hw_setup_display(&dc->hw, &display);
+}
+
+void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc)
+{
+	struct dc_hw_display display;
+
+	display.id = to_vs_display_id(dc, crtc);
+	display.enable = false;
+
+	dc_hw_setup_display(&dc->hw, &display);
+}
+
+void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
+		     struct drm_color_lut *lut, unsigned int size)
+{
+	u16 i, r, g, b;
+	u8 bits, id;
+
+	if (size != dc->hw.info->gamma_size) {
+		drm_err(crtc->dev, "gamma size does not match!\n");
+		return;
+	}
+
+	id = to_vs_display_id(dc, crtc);
+
+	bits = dc->hw.info->gamma_bits;
+	for (i = 0; i < size; i++) {
+		r = drm_color_lut_extract(lut[i].red, bits);
+		g = drm_color_lut_extract(lut[i].green, bits);
+		b = drm_color_lut_extract(lut[i].blue, bits);
+		dc_hw_update_gamma(&dc->hw, id, i, r, g, b);
+	}
+}
+
+void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
+			bool enable)
+{
+	u8 id;
+
+	id = to_vs_display_id(dc, crtc);
+	dc_hw_enable_gamma(&dc->hw, id, enable);
+}
+
+void vs_dc_enable_vblank(struct vs_dc *dc, bool enable)
+{
+	dc_hw_enable_interrupt(&dc->hw, enable);
+}
+
+static u32 calc_factor(u32 src, u32 dest)
+{
+	u32 factor = 1 << 16;
+
+	if (src > 1 && dest > 1)
+		factor = ((src - 1) << 16) / (dest - 1);
+
+	return factor;
+}
+
+static void update_scale(struct drm_plane_state *state, struct dc_hw_roi *roi,
+			 struct dc_hw_scale *scale)
+{
+	int dst_w = drm_rect_width(&state->dst);
+	int dst_h = drm_rect_height(&state->dst);
+	int src_w, src_h, temp;
+
+	scale->enable = false;
+
+	if (roi->enable) {
+		src_w = roi->width;
+		src_h = roi->height;
+	} else {
+		src_w = drm_rect_width(&state->src) >> 16;
+		src_h = drm_rect_height(&state->src) >> 16;
+	}
+
+	if (drm_rotation_90_or_270(state->rotation)) {
+		temp = src_w;
+		src_w = src_h;
+		src_h = temp;
+	}
+
+	if (src_w != dst_w) {
+		scale->scale_factor_x = calc_factor(src_w, dst_w);
+		scale->enable = true;
+	} else {
+		scale->scale_factor_x = 1 << 16;
+	}
+	if (src_h != dst_h) {
+		scale->scale_factor_y = calc_factor(src_h, dst_h);
+		scale->enable = true;
+	} else {
+		scale->scale_factor_y = 1 << 16;
+	}
+}
+
+static void update_fb(struct vs_plane *plane, u8 display_id,
+		      struct dc_hw_fb *fb, struct drm_plane_state *state)
+{
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_framebuffer *drm_fb = state->fb;
+	struct drm_rect *src = &state->src;
+
+	fb->display_id = display_id;
+	fb->y_address = plane_state->dma_addr[0];
+	fb->y_stride = drm_fb->pitches[0];
+	if (drm_fb->format->format == DRM_FORMAT_YVU420) {
+		fb->u_address = plane_state->dma_addr[2];
+		fb->v_address = plane_state->dma_addr[1];
+		fb->u_stride = drm_fb->pitches[2];
+		fb->v_stride = drm_fb->pitches[1];
+	} else {
+		fb->u_address = plane_state->dma_addr[1];
+		fb->v_address = plane_state->dma_addr[2];
+		fb->u_stride = drm_fb->pitches[1];
+		fb->v_stride = drm_fb->pitches[2];
+	}
+	fb->width = drm_rect_width(src) >> 16;
+	fb->height = drm_rect_height(src) >> 16;
+	fb->tile_mode = to_vs_tile_mode(drm_fb->modifier);
+	fb->rotation = to_vs_rotation(state->rotation);
+	fb->yuv_color_space = to_vs_yuv_color_space(state->color_encoding);
+	fb->zpos = state->zpos;
+	fb->enable = state->visible;
+	update_format(drm_fb->format->format, drm_fb->modifier, fb);
+	update_swizzle(drm_fb->format->format, fb);
+	update_watermark(plane_state->watermark, fb);
+	plane_state->status.tile_mode = fb->tile_mode;
+}
+
+static void update_degamma(struct vs_dc *dc, struct vs_plane *plane,
+			   struct vs_plane_state *plane_state)
+{
+	dc_hw_update_degamma(&dc->hw, plane->id, plane_state->degamma);
+	plane_state->degamma_changed = false;
+}
+
+static void update_roi(struct vs_dc *dc, u8 id,
+		       struct vs_plane_state *plane_state,
+		       struct dc_hw_roi *roi,
+		       struct drm_plane_state *state)
+{
+	struct drm_vs_roi *data;
+	struct drm_rect *src = &state->src;
+	u16 src_w = drm_rect_width(src) >> 16;
+	u16 src_h = drm_rect_height(src) >> 16;
+
+	if (plane_state->roi) {
+		data = plane_state->roi->data;
+
+		if (data->enable) {
+			roi->x = data->roi_x;
+			roi->y = data->roi_y;
+			roi->width = (data->roi_x + data->roi_w > src_w) ?
+						 (src_w - data->roi_x) : data->roi_w;
+			roi->height = (data->roi_y + data->roi_h > src_h) ?
+						  (src_h - data->roi_y) : data->roi_h;
+			roi->enable = true;
+		} else {
+			roi->enable = false;
+		}
+
+		dc_hw_update_roi(&dc->hw, id, roi);
+	} else {
+		roi->enable = false;
+	}
+}
+
+static void update_color_mgmt(struct vs_dc *dc, u8 id,
+			      struct dc_hw_fb *fb,
+			      struct vs_plane_state *plane_state)
+{
+	struct drm_vs_color_mgmt *data;
+	struct dc_hw_colorkey colorkey;
+
+	if (plane_state->color_mgmt) {
+		data = plane_state->color_mgmt->data;
+
+		fb->clear_enable = data->clear_enable;
+		fb->clear_value = data->clear_value;
+
+		if (data->colorkey > data->colorkey_high)
+			data->colorkey = data->colorkey_high;
+
+		colorkey.colorkey = data->colorkey;
+		colorkey.colorkey_high = data->colorkey_high;
+		colorkey.transparency = (data->transparency) ?
+				DC_TRANSPARENCY_KEY : DC_TRANSPARENCY_OPAQUE;
+		dc_hw_update_colorkey(&dc->hw, id, &colorkey);
+	}
+}
+
+static void update_plane(struct vs_dc *dc, struct vs_plane *plane,
+			 struct drm_plane *drm_plane,
+			 struct drm_atomic_state *drm_state)
+{
+	struct dc_hw_fb fb = {0};
+	struct dc_hw_scale scale;
+	struct dc_hw_position pos;
+	struct dc_hw_blend blend;
+	struct dc_hw_roi roi;
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
+									   drm_plane);
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_rect *dest = &state->dst;
+	bool dec_enable = false;
+	u8 display_id = 0;
+
+	display_id = to_vs_display_id(dc, state->crtc);
+	update_fb(plane, display_id, &fb, state);
+	fb.dec_enable = dec_enable;
+
+	update_roi(dc, plane->id, plane_state, &roi, state);
+
+	update_scale(state, &roi, &scale);
+
+	if (plane_state->degamma_changed)
+		update_degamma(dc, plane, plane_state);
+
+	pos.start_x = dest->x1;
+	pos.start_y = dest->y1;
+	pos.end_x = dest->x2;
+	pos.end_y = dest->y2;
+
+	blend.alpha = (u8)(state->alpha >> 8);
+	blend.blend_mode = (u8)(state->pixel_blend_mode);
+
+	update_color_mgmt(dc, plane->id, &fb, plane_state);
+
+	dc_hw_update_plane(&dc->hw, plane->id, &fb, &scale, &pos, &blend);
+}
+
+static void update_qos(struct vs_dc *dc, struct vs_plane *plane,
+		       struct drm_plane *drm_plane,
+		       struct drm_atomic_state *drm_state)
+{
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
+									   drm_plane);
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_vs_watermark *data;
+	struct dc_hw_qos qos;
+
+	if (plane_state->watermark) {
+		data = plane_state->watermark->data;
+
+		if (data->qos_high) {
+			if (data->qos_low > data->qos_high)
+				data->qos_low = data->qos_high;
+
+			qos.low_value = data->qos_low & 0x0F;
+			qos.high_value = data->qos_high & 0x0F;
+			dc_hw_update_qos(&dc->hw, &qos);
+		}
+	}
+}
+
+static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor)
+{
+	u8 size_type;
+
+	switch (state->crtc_w) {
+	case 32:
+		size_type = CURSOR_SIZE_32X32;
+		break;
+	case 64:
+		size_type = CURSOR_SIZE_64X64;
+		break;
+	default:
+		size_type = CURSOR_SIZE_32X32;
+		break;
+	}
+
+	cursor->size = size_type;
+}
+
+static void update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
+				struct drm_plane *drm_plane,
+				struct drm_atomic_state *drm_state)
+{
+	struct drm_plane_state *state = drm_atomic_get_new_plane_state(drm_state,
+								       drm_plane);
+	struct vs_plane_state *plane_state = to_vs_plane_state(state);
+	struct drm_framebuffer *drm_fb = state->fb;
+	struct dc_hw_cursor cursor;
+
+	cursor.address = plane_state->dma_addr[0];
+	cursor.x = state->crtc_x;
+	cursor.y = state->crtc_y;
+	cursor.hot_x = drm_fb->hot_x;
+	cursor.hot_y = drm_fb->hot_y;
+	cursor.display_id = to_vs_display_id(dc, state->crtc);
+	update_cursor_size(state, &cursor);
+	cursor.enable = true;
+
+	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
+}
+
+void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
+			struct drm_plane *drm_plane,
+			struct drm_atomic_state *drm_state)
+{
+	update_plane(dc, plane, drm_plane, drm_state);
+	update_qos(dc, plane, drm_plane, drm_state);
+}
+
+void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
+			       struct drm_plane *drm_plane,
+			       struct drm_atomic_state *drm_state)
+{
+	update_cursor_plane(dc, plane, drm_plane, drm_state);
+}
+
+void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
+			 struct drm_plane_state *old_state)
+{
+	struct dc_hw_fb fb = {0};
+
+	fb.enable = false;
+	dc_hw_update_plane(&dc->hw, plane->id, &fb, NULL, NULL, NULL);
+}
+
+void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
+				struct drm_plane_state *old_state)
+{
+	struct dc_hw_cursor cursor = {0};
+
+	cursor.enable = false;
+	cursor.display_id = to_vs_display_id(dc, old_state->crtc);
+	dc_hw_update_cursor(&dc->hw, cursor.display_id, &cursor);
+}
+
+static bool vs_dc_mod_supported(const struct vs_plane_info *plane_info,
+				u64 modifier)
+{
+	const u64 *mods;
+
+	if (!plane_info->modifiers)
+		return false;
+
+	for (mods = plane_info->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
+		if (*mods == modifier)
+			return true;
+	}
+
+	return false;
+}
+
+int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
+		      struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+										 plane);
+
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	const struct vs_plane_info *plane_info;
+	struct drm_crtc *crtc = new_plane_state->crtc;
+	struct drm_crtc_state *crtc_state;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+
+	plane_info = &dc->hw.info->planes[vs_plane->id];
+
+	if (fb->width < plane_info->min_width ||
+	    fb->width > plane_info->max_width ||
+	    fb->height < plane_info->min_height ||
+	    fb->height > plane_info->max_height)
+		drm_err_once(plane->dev, "buffer size may not support on plane%d.\n",
+			     vs_plane->id);
+
+	if (!vs_dc_mod_supported(plane_info, fb->modifier)) {
+		drm_err(plane->dev, "unsupported modifier on plane%d.\n", vs_plane->id);
+		return -EINVAL;
+	}
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
+						  plane_info->min_scale,
+						  plane_info->max_scale,
+						  true, true);
+}
+
+int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
+			     struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+									   plane);
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	const struct vs_plane_info *plane_info;
+	struct drm_crtc *crtc = new_plane_state->crtc;
+	struct drm_crtc_state *crtc_state;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+
+	plane_info = &dc->hw.info->planes[vs_plane->id];
+
+	if (fb->width < plane_info->min_width ||
+	    fb->width > plane_info->max_width ||
+	    fb->height < plane_info->min_height ||
+	    fb->height > plane_info->max_height)
+		drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", vs_plane->id);
+
+	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state))
+		return -EINVAL;
+
+	return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
+						plane_info->min_scale,
+						plane_info->max_scale,
+						true, true);
+}
+
+static void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
+{
+	struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
+
+	drm_crtc_handle_vblank(crtc);
+
+	vs_crtc_state->underflow = underflow;
+}
+
+static irqreturn_t dc_isr(int irq, void *data)
+{
+	struct vs_dc *dc = data;
+	struct vs_dc_info *dc_info = dc->hw.info;
+	u32 i, ret;
+
+	ret = dc_hw_get_interrupt(&dc->hw);
+
+	for (i = 0; i < dc_info->panel_num; i++)
+		vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
+
+	return IRQ_HANDLED;
+}
+
+void vs_dc_commit(struct vs_dc *dc)
+{
+	dc_hw_enable_shadow_register(&dc->hw, false);
+
+	dc_hw_commit(&dc->hw);
+
+	if (dc->first_frame)
+		dc->first_frame = false;
+
+	dc_hw_enable_shadow_register(&dc->hw, true);
+}
+
+static int dc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm_dev = data;
+	struct vs_dc *dc = dev_get_drvdata(dev);
+	struct device_node *port;
+	struct vs_crtc *crtc;
+	struct vs_dc_info *dc_info;
+	struct vs_plane *plane;
+	struct vs_plane_info *plane_info;
+	int i, ret;
+	u32 ctrc_mask = 0;
+
+	if (!drm_dev || !dc) {
+		dev_err(dev, "devices are not created.\n");
+		return -ENODEV;
+	}
+
+	ret = dc_init(dev);
+	if (ret < 0) {
+		drm_err(drm_dev, "Failed to initialize DC hardware.\n");
+		return ret;
+	}
+
+	port = of_get_child_by_name(dev->of_node, "port");
+	if (!port) {
+		drm_err(drm_dev, "no port node found\n");
+		return -ENODEV;
+	}
+	of_node_put(port);
+
+	dc_info = dc->hw.info;
+
+	for (i = 0; i < dc_info->panel_num; i++) {
+		crtc = vs_crtc_create(drm_dev, dc_info);
+		if (!crtc) {
+			drm_err(drm_dev, "Failed to create CRTC.\n");
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		crtc->base.port = port;
+		crtc->dev = dev;
+		dc->crtc[i] = crtc;
+		ctrc_mask |= drm_crtc_mask(&crtc->base);
+	}
+
+	for (i = 0; i < dc_info->plane_num; i++) {
+		plane_info = (struct vs_plane_info *)&dc_info->planes[i];
+
+		if (!strcmp(plane_info->name, "Primary") || !strcmp(plane_info->name, "Cursor")) {
+			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
+						drm_crtc_mask(&dc->crtc[0]->base));
+		} else if (!strcmp(plane_info->name, "Primary_1") ||
+				   !strcmp(plane_info->name, "Cursor_1")) {
+			plane = vs_plane_create(drm_dev, plane_info, dc_info->layer_num,
+						drm_crtc_mask(&dc->crtc[1]->base));
+		} else {
+			plane = vs_plane_create(drm_dev, plane_info,
+						dc_info->layer_num, ctrc_mask);
+		}
+
+		if (IS_ERR(plane)) {
+			dev_err(dev, "failed to construct plane\n");
+			return PTR_ERR(plane);
+		}
+
+		plane->id = i;
+		dc->planes[i].id = plane_info->id;
+
+		if (plane_info->type == DRM_PLANE_TYPE_PRIMARY) {
+			if (!strcmp(plane_info->name, "Primary"))
+				dc->crtc[0]->base.primary = &plane->base;
+			else
+				dc->crtc[1]->base.primary = &plane->base;
+			drm_dev->mode_config.min_width = plane_info->min_width;
+			drm_dev->mode_config.min_height =
+							plane_info->min_height;
+			drm_dev->mode_config.max_width = plane_info->max_width;
+			drm_dev->mode_config.max_height =
+							plane_info->max_height;
+		}
+
+		if (plane_info->type == DRM_PLANE_TYPE_CURSOR) {
+			if (!strcmp(plane_info->name, "Cursor"))
+				dc->crtc[0]->base.cursor = &plane->base;
+			else
+				dc->crtc[1]->base.cursor = &plane->base;
+			drm_dev->mode_config.cursor_width =
+							plane_info->max_width;
+			drm_dev->mode_config.cursor_height =
+							plane_info->max_height;
+		}
+	}
+
+	vs_drm_update_pitch_alignment(drm_dev, dc_info->pitch_alignment);
+	return 0;
+}
+
+static void dc_unbind(struct device *dev, struct device *master, void *data)
+{
+	dc_deinit(dev);
+}
+
+const struct component_ops dc_component_ops = {
+	.bind = dc_bind,
+	.unbind = dc_unbind,
+};
+
+static const struct of_device_id dc_driver_dt_match[] = {
+	{ .compatible = "starfive,jh7110-dc8200", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dc_driver_dt_match);
+
+static int dc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct vs_dc *dc;
+	int irq, ret, i;
+
+	dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL);
+	if (!dc)
+		return -ENOMEM;
+
+	dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(dc->hw.hi_base))
+		return PTR_ERR(dc->hw.hi_base);
+
+	dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(dc->hw.reg_base))
+		return PTR_ERR(dc->hw.reg_base);
+
+	dc->nclks = ARRAY_SIZE(dc->clk_vout);
+	for (i = 0; i < dc->nclks; ++i)
+		dc->clk_vout[i].id = vout_clocks[i];
+	ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout);
+	if (ret) {
+		dev_err(dev, "Failed to get clk controls\n");
+		return ret;
+	}
+
+	dc->nrsts = ARRAY_SIZE(dc->rst_vout);
+	for (i = 0; i < dc->nrsts; ++i)
+		dc->rst_vout[i].id = vout_resets[i];
+	ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts,
+						 dc->rst_vout);
+	if (ret) {
+		dev_err(dev, "Failed to get reset controls\n");
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+
+	ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc);
+	if (ret < 0) {
+		dev_err(dev, "Failed to install irq:%u.\n", irq);
+		return ret;
+	}
+
+	dev_set_drvdata(dev, dc);
+
+	return component_add(dev, &dc_component_ops);
+}
+
+static int dc_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	component_del(dev, &dc_component_ops);
+
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+struct platform_driver dc_platform_driver = {
+	.probe = dc_probe,
+	.remove = dc_remove,
+	.driver = {
+		.name = "vs-dc",
+		.of_match_table = of_match_ptr(dc_driver_dt_match),
+	},
+};
+
+MODULE_AUTHOR("StarFive Corporation");
+MODULE_DESCRIPTION("VeriSilicon DC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/verisilicon/vs_dc.h b/drivers/gpu/drm/verisilicon/vs_dc.h
new file mode 100644
index 000000000..8e96fd32c
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc.h
@@ -0,0 +1,80 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DC_H__
+#define __VS_DC_H__
+
+#include <linux/clk.h>
+#include <linux/mm_types.h>
+#include <linux/reset.h>
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modes.h>
+
+#include "vs_crtc.h"
+#include "vs_dc_hw.h"
+#include "vs_plane.h"
+
+struct vs_dc_plane {
+	enum dc_hw_plane_id id;
+};
+
+enum vout_clk {
+	CLK_VOUT_NOC_DISP = 0,
+	CLK_VOUT_PIX0,
+	CLK_VOUT_PIX1,
+	CLK_VOUT_CORE,
+	CLK_VOUT_AXI,
+	CLK_VOUT_AHB,
+	CLK_VOUT_HDMI_PIX,
+	CLK_VOUT_SOC_PIX,
+	CLK_VOUT_NUM
+};
+
+enum rst_vout {
+	RST_VOUT_AXI = 0,
+	RST_VOUT_AHB,
+	RST_VOUT_CORE,
+	RST_VOUT_NUM
+};
+
+struct vs_dc {
+	struct vs_crtc		*crtc[DC_DISPLAY_NUM];
+	struct dc_hw		hw;
+	bool			first_frame;
+
+	struct vs_dc_plane	planes[PLANE_NUM];
+	struct clk_bulk_data	clk_vout[CLK_VOUT_NUM];
+	int			nclks;
+	struct reset_control_bulk_data rst_vout[RST_VOUT_NUM];
+	int			nrsts;
+};
+
+void vs_dc_enable(struct vs_dc *dc, struct drm_crtc *crtc);
+void vs_dc_disable(struct vs_dc *dc, struct drm_crtc *crtc);
+
+void vs_dc_set_gamma(struct vs_dc *dc, struct drm_crtc *crtc,
+		     struct drm_color_lut *lut, unsigned int size);
+void vs_dc_enable_gamma(struct vs_dc *dc, struct drm_crtc *crtc, bool enable);
+void vs_dc_enable_vblank(struct vs_dc *dc, bool enable);
+void vs_dc_commit(struct vs_dc *dc);
+void vs_dc_update_plane(struct vs_dc *dc, struct vs_plane *plane,
+			struct drm_plane *drm_plane,
+			struct drm_atomic_state *drm_state);
+void vs_dc_disable_plane(struct vs_dc *dc, struct vs_plane *plane,
+			 struct drm_plane_state *old_state);
+int vs_dc_check_plane(struct vs_dc *dc, struct drm_plane *plane,
+		      struct drm_atomic_state *state);
+void vs_dc_update_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
+			       struct drm_plane *drm_plane,
+			       struct drm_atomic_state *drm_state);
+void vs_dc_disable_cursor_plane(struct vs_dc *dc, struct vs_plane *plane,
+				struct drm_plane_state *old_state);
+int vs_dc_check_cursor_plane(struct vs_dc *dc, struct drm_plane *plane,
+			     struct drm_atomic_state *state);
+
+extern struct platform_driver dc_platform_driver;
+
+#endif /* __VS_DC_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.c b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
new file mode 100644
index 000000000..e5acb7eb4
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.c
@@ -0,0 +1,1959 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/io.h>
+#include <linux/media-bus-format.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_fourcc.h>
+#include <drm/vs_drm.h>
+
+#include "vs_dc_hw.h"
+#include "vs_type.h"
+
+static const u32 horkernel[] = {
+	0x00000000, 0x20000000, 0x00002000, 0x00000000,
+	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
+	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
+	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
+	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
+	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
+	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
+	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
+	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
+	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
+	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
+	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
+	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
+	0x00000000, 0x00000000, 0x00000000, 0x01470000,
+	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
+	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
+	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
+	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00004000, 0x00000000,
+	0x00000000, 0x00000000, 0x20002000, 0x00000000,
+	0x00000000, 0x00000000, 0x1c030000, 0x000023fd,
+	0x00000000, 0x00000000, 0x00000000, 0x27e1181f,
+	0x00000000, 0x00000000, 0x00000000, 0x14680000,
+	0x00002b98, 0x00000000, 0x00000000, 0x00000000,
+	0x2f1010f0, 0x00000000, 0x00000000, 0x00000000,
+	0x0dc70000, 0x00003239, 0x00000000, 0x00000000,
+	0x00000000, 0x350b0af5, 0x00000000, 0x00000000,
+	0x00000000, 0x087f0000, 0x00003781, 0x00000000,
+	0x00000000, 0x00000000, 0x399a0666, 0x00000000,
+	0x00000000, 0x00000000, 0x04a70000, 0x00003b59,
+	0x00000000, 0x00000000, 0x00000000, 0x3cc4033c,
+	0x00000000, 0x00000000, 0x00000000, 0x021f0000,
+};
+
+#define H_COEF_SIZE (sizeof(horkernel) / sizeof(u32))
+
+static const u32 verkernel[] = {
+	0x00000000, 0x20000000, 0x00002000, 0x00000000,
+	0x00000000, 0x00000000, 0x23fd1c03, 0x00000000,
+	0x00000000, 0x00000000, 0x181f0000, 0x000027e1,
+	0x00000000, 0x00000000, 0x00000000, 0x2b981468,
+	0x00000000, 0x00000000, 0x00000000, 0x10f00000,
+	0x00002f10, 0x00000000, 0x00000000, 0x00000000,
+	0x32390dc7, 0x00000000, 0x00000000, 0x00000000,
+	0x0af50000, 0x0000350b, 0x00000000, 0x00000000,
+	0x00000000, 0x3781087f, 0x00000000, 0x00000000,
+	0x00000000, 0x06660000, 0x0000399a, 0x00000000,
+	0x00000000, 0x00000000, 0x3b5904a7, 0x00000000,
+	0x00000000, 0x00000000, 0x033c0000, 0x00003cc4,
+	0x00000000, 0x00000000, 0x00000000, 0x3de1021f,
+	0x00000000, 0x00000000, 0x00000000, 0x01470000,
+	0x00003eb9, 0x00000000, 0x00000000, 0x00000000,
+	0x3f5300ad, 0x00000000, 0x00000000, 0x00000000,
+	0x00480000, 0x00003fb8, 0x00000000, 0x00000000,
+	0x00000000, 0x3fef0011, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00004000, 0x00000000,
+	0xcdcd0000, 0xfdfdfdfd, 0xabababab, 0xabababab,
+	0x00000000, 0x00000000, 0x5ff5f456, 0x000f5f58,
+	0x02cc6c78, 0x02cc0c28, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+	0xfeeefeee, 0xfeeefeee, 0xfeeefeee, 0xfeeefeee,
+};
+
+#define V_COEF_SIZE (sizeof(verkernel) / sizeof(u32))
+
+/*
+ * RGB 709->2020 conversion parameters
+ */
+static u16 RGB2RGB[RGB_TO_RGB_TABLE_SIZE] = {
+	10279,	5395,	709,
+	1132,	15065,	187,
+	269,	1442,	14674
+};
+
+/*
+ * YUV601 to RGB conversion parameters
+ * YUV2RGB[0]  - [8] : C0 - C8;
+ * YUV2RGB[9]  - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV601_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+	1196,	0,			1640,	1196,
+	-404,	-836,		1196,	2076,
+	0,		-916224,	558336,	-1202944,
+	64,		 940,		64,		960
+};
+
+/*
+ * YUV709 to RGB conversion parameters
+ * YUV2RGB[0]  - [8] : C0 - C8;
+ * YUV2RGB[9]  - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV709_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+	1196,		0,		1844,	1196,
+	-220,		-548,	1196,	2172,
+	0,			-1020672, 316672,  -1188608,
+	64,			940,		64,		960
+};
+
+/*
+ * YUV2020 to RGB conversion parameters
+ * YUV2RGB[0]  - [8] : C0 - C8;
+ * YUV2RGB[9]  - [11]: D0 - D2;
+ * YUV2RGB[12] - [13]: Y clamp min & max calue;
+ * YUV2RGB[14] - [15]: UV clamp min & max calue;
+ */
+static s32 YUV2020_2RGB[YUV_TO_RGB_TABLE_SIZE] = {
+	1196, 0, 1724, 1196,
+	-192, -668, 1196, 2200,
+	0, -959232, 363776, -1202944,
+	64, 940, 64, 960
+};
+
+/*
+ * RGB to YUV2020 conversion parameters
+ * RGB2YUV[0] - [8] : C0 - C8;
+ * RGB2YUV[9] - [11]: D0 - D2;
+ */
+static s16 RGB2YUV[RGB_TO_YUV_TABLE_SIZE] = {
+	230,	594,	52,
+	-125,  -323,	448,
+	448,   -412,   -36,
+	64,		512,	512
+};
+
+/*
+ * Degamma table for 709 color space data.
+ */
+static u16 DEGAMMA_709[DEGAMMA_SIZE] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0005,
+	0x0007, 0x000a, 0x000d, 0x0011, 0x0015, 0x0019, 0x001e, 0x0024,
+	0x002a, 0x0030, 0x0038, 0x003f, 0x0048, 0x0051, 0x005a, 0x0064,
+	0x006f, 0x007b, 0x0087, 0x0094, 0x00a1, 0x00af, 0x00be, 0x00ce,
+	0x00de, 0x00ef, 0x0101, 0x0114, 0x0127, 0x013b, 0x0150, 0x0166,
+	0x017c, 0x0193, 0x01ac, 0x01c4, 0x01de, 0x01f9, 0x0214, 0x0230,
+	0x024d, 0x026b, 0x028a, 0x02aa, 0x02ca, 0x02ec, 0x030e, 0x0331,
+	0x0355, 0x037a, 0x03a0, 0x03c7, 0x03ef, 0x0418, 0x0441, 0x046c,
+	0x0498, 0x04c4, 0x04f2, 0x0520, 0x0550, 0x0581, 0x05b2, 0x05e5,
+	0x0618, 0x064d, 0x0682, 0x06b9, 0x06f0, 0x0729, 0x0763, 0x079d,
+	0x07d9, 0x0816, 0x0854, 0x0893, 0x08d3, 0x0914, 0x0956, 0x0999,
+	0x09dd, 0x0a23, 0x0a69, 0x0ab1, 0x0afa, 0x0b44, 0x0b8f, 0x0bdb,
+	0x0c28, 0x0c76, 0x0cc6, 0x0d17, 0x0d69, 0x0dbb, 0x0e10, 0x0e65,
+	0x0ebb, 0x0f13, 0x0f6c, 0x0fc6, 0x1021, 0x107d, 0x10db, 0x113a,
+	0x119a, 0x11fb, 0x125d, 0x12c1, 0x1325, 0x138c, 0x13f3, 0x145b,
+	0x14c5, 0x1530, 0x159c, 0x160a, 0x1678, 0x16e8, 0x175a, 0x17cc,
+	0x1840, 0x18b5, 0x192b, 0x19a3, 0x1a1c, 0x1a96, 0x1b11, 0x1b8e,
+	0x1c0c, 0x1c8c, 0x1d0c, 0x1d8e, 0x1e12, 0x1e96, 0x1f1c, 0x1fa3,
+	0x202c, 0x20b6, 0x2141, 0x21ce, 0x225c, 0x22eb, 0x237c, 0x240e,
+	0x24a1, 0x2536, 0x25cc, 0x2664, 0x26fc, 0x2797, 0x2832, 0x28cf,
+	0x296e, 0x2a0e, 0x2aaf, 0x2b51, 0x2bf5, 0x2c9b, 0x2d41, 0x2dea,
+	0x2e93, 0x2f3e, 0x2feb, 0x3099, 0x3148, 0x31f9, 0x32ab, 0x335f,
+	0x3414, 0x34ca, 0x3582, 0x363c, 0x36f7, 0x37b3, 0x3871, 0x3930,
+	0x39f1, 0x3ab3, 0x3b77, 0x3c3c, 0x3d02, 0x3dcb, 0x3e94, 0x3f5f,
+	0x402c, 0x40fa, 0x41ca, 0x429b, 0x436d, 0x4442, 0x4517, 0x45ee,
+	0x46c7, 0x47a1, 0x487d, 0x495a, 0x4a39, 0x4b19, 0x4bfb, 0x4cde,
+	0x4dc3, 0x4eaa, 0x4f92, 0x507c, 0x5167, 0x5253, 0x5342, 0x5431,
+	0x5523, 0x5616, 0x570a, 0x5800, 0x58f8, 0x59f1, 0x5aec, 0x5be9,
+	0x5ce7, 0x5de6, 0x5ee7, 0x5fea, 0x60ef, 0x61f5, 0x62fc, 0x6406,
+	0x6510, 0x661d, 0x672b, 0x683b, 0x694c, 0x6a5f, 0x6b73, 0x6c8a,
+	0x6da2, 0x6ebb, 0x6fd6, 0x70f3, 0x7211, 0x7331, 0x7453, 0x7576,
+	0x769b, 0x77c2, 0x78ea, 0x7a14, 0x7b40, 0x7c6d, 0x7d9c, 0x7ecd,
+	0x3f65, 0x3f8c, 0x3fb2, 0x3fd8
+};
+
+/*
+ * Degamma table for 2020 color space data.
+ */
+static u16 DEGAMMA_2020[DEGAMMA_SIZE] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+	0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003,
+	0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0006,
+	0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, 0x0009, 0x000a,
+	0x000a, 0x000b, 0x000c, 0x000c, 0x000d, 0x000e, 0x000f, 0x000f,
+	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0016, 0x0017, 0x0018,
+	0x0019, 0x001b, 0x001c, 0x001e, 0x001f, 0x0021, 0x0022, 0x0024,
+	0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, 0x0033, 0x0035,
+	0x0038, 0x003a, 0x003d, 0x0040, 0x0043, 0x0046, 0x0049, 0x004d,
+	0x0050, 0x0054, 0x0057, 0x005b, 0x005f, 0x0064, 0x0068, 0x006d,
+	0x0071, 0x0076, 0x007c, 0x0081, 0x0086, 0x008c, 0x0092, 0x0098,
+	0x009f, 0x00a5, 0x00ac, 0x00b4, 0x00bb, 0x00c3, 0x00cb, 0x00d3,
+	0x00dc, 0x00e5, 0x00ee, 0x00f8, 0x0102, 0x010c, 0x0117, 0x0123,
+	0x012e, 0x013a, 0x0147, 0x0154, 0x0161, 0x016f, 0x017e, 0x018d,
+	0x019c, 0x01ac, 0x01bd, 0x01ce, 0x01e0, 0x01f3, 0x0206, 0x021a,
+	0x022f, 0x0244, 0x025a, 0x0272, 0x0289, 0x02a2, 0x02bc, 0x02d6,
+	0x02f2, 0x030f, 0x032c, 0x034b, 0x036b, 0x038b, 0x03ae, 0x03d1,
+	0x03f5, 0x041b, 0x0443, 0x046b, 0x0495, 0x04c1, 0x04ee, 0x051d,
+	0x054e, 0x0580, 0x05b4, 0x05ea, 0x0622, 0x065c, 0x0698, 0x06d6,
+	0x0717, 0x075a, 0x079f, 0x07e7, 0x0831, 0x087e, 0x08cd, 0x0920,
+	0x0976, 0x09ce, 0x0a2a, 0x0a89, 0x0aec, 0x0b52, 0x0bbc, 0x0c2a,
+	0x0c9b, 0x0d11, 0x0d8b, 0x0e0a, 0x0e8d, 0x0f15, 0x0fa1, 0x1033,
+	0x10ca, 0x1167, 0x120a, 0x12b2, 0x1360, 0x1415, 0x14d1, 0x1593,
+	0x165d, 0x172e, 0x1806, 0x18e7, 0x19d0, 0x1ac1, 0x1bbb, 0x1cbf,
+	0x1dcc, 0x1ee3, 0x2005, 0x2131, 0x2268, 0x23ab, 0x24fa, 0x2656,
+	0x27be, 0x2934, 0x2ab8, 0x2c4a, 0x2dec, 0x2f9d, 0x315f, 0x3332,
+	0x3516, 0x370d, 0x3916, 0x3b34, 0x3d66, 0x3fad, 0x420b, 0x4480,
+	0x470d, 0x49b3, 0x4c73, 0x4f4e, 0x5246, 0x555a, 0x588e, 0x5be1,
+	0x5f55, 0x62eb, 0x66a6, 0x6a86, 0x6e8c, 0x72bb, 0x7714, 0x7b99,
+	0x3dcb, 0x3e60, 0x3ef5, 0x3f8c
+};
+
+/* one is for primary plane and the other is for all overlay planes */
+static const struct dc_hw_plane_reg dc_plane_reg[] = {
+	{
+	.y_address		= DC_FRAMEBUFFER_ADDRESS,
+	.u_address		= DC_FRAMEBUFFER_U_ADDRESS,
+	.v_address		= DC_FRAMEBUFFER_V_ADDRESS,
+	.y_stride		= DC_FRAMEBUFFER_STRIDE,
+	.u_stride		= DC_FRAMEBUFFER_U_STRIDE,
+	.v_stride		= DC_FRAMEBUFFER_V_STRIDE,
+	.size			= DC_FRAMEBUFFER_SIZE,
+	.top_left		= DC_FRAMEBUFFER_TOP_LEFT,
+	.bottom_right	= DC_FRAMEBUFFER_BOTTOM_RIGHT,
+	.scale_factor_x			= DC_FRAMEBUFFER_SCALE_FACTOR_X,
+	.scale_factor_y			= DC_FRAMEBUFFER_SCALE_FACTOR_Y,
+	.h_filter_coef_index	= DC_FRAMEBUFFER_H_FILTER_COEF_INDEX,
+	.h_filter_coef_data		= DC_FRAMEBUFFER_H_FILTER_COEF_DATA,
+	.v_filter_coef_index	= DC_FRAMEBUFFER_V_FILTER_COEF_INDEX,
+	.v_filter_coef_data		= DC_FRAMEBUFFER_V_FILTER_COEF_DATA,
+	.init_offset			= DC_FRAMEBUFFER_INIT_OFFSET,
+	.color_key				= DC_FRAMEBUFFER_COLOR_KEY,
+	.color_key_high			= DC_FRAMEBUFFER_COLOR_KEY_HIGH,
+	.clear_value			= DC_FRAMEBUFFER_CLEAR_VALUE,
+	.color_table_index		= DC_FRAMEBUFFER_COLOR_TABLE_INDEX,
+	.color_table_data		= DC_FRAMEBUFFER_COLOR_TABLE_DATA,
+	.scale_config			= DC_FRAMEBUFFER_SCALE_CONFIG,
+	.water_mark				= DC_FRAMEBUFFER_WATER_MARK,
+	.degamma_index			= DC_FRAMEBUFFER_DEGAMMA_INDEX,
+	.degamma_data			= DC_FRAMEBUFFER_DEGAMMA_DATA,
+	.degamma_ex_data		= DC_FRAMEBUFFER_DEGAMMA_EX_DATA,
+	.src_global_color		= DC_FRAMEBUFFER_SRC_GLOBAL_COLOR,
+	.dst_global_color		= DC_FRAMEBUFFER_DST_GLOBAL_COLOR,
+	.blend_config			= DC_FRAMEBUFFER_BLEND_CONFIG,
+	.roi_origin				= DC_FRAMEBUFFER_ROI_ORIGIN,
+	.roi_size				= DC_FRAMEBUFFER_ROI_SIZE,
+	.yuv_to_rgb_coef0			= DC_FRAMEBUFFER_YUVTORGB_COEF0,
+	.yuv_to_rgb_coef1			= DC_FRAMEBUFFER_YUVTORGB_COEF1,
+	.yuv_to_rgb_coef2			= DC_FRAMEBUFFER_YUVTORGB_COEF2,
+	.yuv_to_rgb_coef3			= DC_FRAMEBUFFER_YUVTORGB_COEF3,
+	.yuv_to_rgb_coef4			= DC_FRAMEBUFFER_YUVTORGB_COEF4,
+	.yuv_to_rgb_coefd0			= DC_FRAMEBUFFER_YUVTORGB_COEFD0,
+	.yuv_to_rgb_coefd1			= DC_FRAMEBUFFER_YUVTORGB_COEFD1,
+	.yuv_to_rgb_coefd2			= DC_FRAMEBUFFER_YUVTORGB_COEFD2,
+	.y_clamp_bound				= DC_FRAMEBUFFER_Y_CLAMP_BOUND,
+	.uv_clamp_bound				= DC_FRAMEBUFFER_UV_CLAMP_BOUND,
+	.rgb_to_rgb_coef0			= DC_FRAMEBUFFER_RGBTORGB_COEF0,
+	.rgb_to_rgb_coef1			= DC_FRAMEBUFFER_RGBTORGB_COEF1,
+	.rgb_to_rgb_coef2			= DC_FRAMEBUFFER_RGBTORGB_COEF2,
+	.rgb_to_rgb_coef3			= DC_FRAMEBUFFER_RGBTORGB_COEF3,
+	.rgb_to_rgb_coef4			= DC_FRAMEBUFFER_RGBTORGB_COEF4,
+	},
+	{
+	.y_address		= DC_OVERLAY_ADDRESS,
+	.u_address		= DC_OVERLAY_U_ADDRESS,
+	.v_address		= DC_OVERLAY_V_ADDRESS,
+	.y_stride		= DC_OVERLAY_STRIDE,
+	.u_stride		= DC_OVERLAY_U_STRIDE,
+	.v_stride		= DC_OVERLAY_V_STRIDE,
+	.size			= DC_OVERLAY_SIZE,
+	.top_left		= DC_OVERLAY_TOP_LEFT,
+	.bottom_right	= DC_OVERLAY_BOTTOM_RIGHT,
+	.scale_factor_x	= DC_OVERLAY_SCALE_FACTOR_X,
+	.scale_factor_y	= DC_OVERLAY_SCALE_FACTOR_Y,
+	.h_filter_coef_index = DC_OVERLAY_H_FILTER_COEF_INDEX,
+	.h_filter_coef_data  = DC_OVERLAY_H_FILTER_COEF_DATA,
+	.v_filter_coef_index = DC_OVERLAY_V_FILTER_COEF_INDEX,
+	.v_filter_coef_data  = DC_OVERLAY_V_FILTER_COEF_DATA,
+	.init_offset		 = DC_OVERLAY_INIT_OFFSET,
+	.color_key			 = DC_OVERLAY_COLOR_KEY,
+	.color_key_high			= DC_OVERLAY_COLOR_KEY_HIGH,
+	.clear_value		 = DC_OVERLAY_CLEAR_VALUE,
+	.color_table_index	 = DC_OVERLAY_COLOR_TABLE_INDEX,
+	.color_table_data	 = DC_OVERLAY_COLOR_TABLE_DATA,
+	.scale_config		 = DC_OVERLAY_SCALE_CONFIG,
+	.water_mark				= DC_OVERLAY_WATER_MARK,
+	.degamma_index		 = DC_OVERLAY_DEGAMMA_INDEX,
+	.degamma_data		 = DC_OVERLAY_DEGAMMA_DATA,
+	.degamma_ex_data	 = DC_OVERLAY_DEGAMMA_EX_DATA,
+	.src_global_color	 = DC_OVERLAY_SRC_GLOBAL_COLOR,
+	.dst_global_color	 = DC_OVERLAY_DST_GLOBAL_COLOR,
+	.blend_config		 = DC_OVERLAY_BLEND_CONFIG,
+	.roi_origin				= DC_OVERLAY_ROI_ORIGIN,
+	.roi_size				= DC_OVERLAY_ROI_SIZE,
+	.yuv_to_rgb_coef0		 = DC_OVERLAY_YUVTORGB_COEF0,
+	.yuv_to_rgb_coef1		 = DC_OVERLAY_YUVTORGB_COEF1,
+	.yuv_to_rgb_coef2		 = DC_OVERLAY_YUVTORGB_COEF2,
+	.yuv_to_rgb_coef3		 = DC_OVERLAY_YUVTORGB_COEF3,
+	.yuv_to_rgb_coef4			= DC_OVERLAY_YUVTORGB_COEF4,
+	.yuv_to_rgb_coefd0			= DC_OVERLAY_YUVTORGB_COEFD0,
+	.yuv_to_rgb_coefd1			= DC_OVERLAY_YUVTORGB_COEFD1,
+	.yuv_to_rgb_coefd2			= DC_OVERLAY_YUVTORGB_COEFD2,
+	.y_clamp_bound		 = DC_OVERLAY_Y_CLAMP_BOUND,
+	.uv_clamp_bound		 = DC_OVERLAY_UV_CLAMP_BOUND,
+	.rgb_to_rgb_coef0		 = DC_OVERLAY_RGBTORGB_COEF0,
+	.rgb_to_rgb_coef1		 = DC_OVERLAY_RGBTORGB_COEF1,
+	.rgb_to_rgb_coef2		 = DC_OVERLAY_RGBTORGB_COEF2,
+	.rgb_to_rgb_coef3		 = DC_OVERLAY_RGBTORGB_COEF3,
+	.rgb_to_rgb_coef4		 = DC_OVERLAY_RGBTORGB_COEF4,
+	},
+};
+
+static const u32 primary_overlay_format0[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_XBGR4444,
+	DRM_FORMAT_RGBX4444,
+	DRM_FORMAT_BGRX4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_ABGR4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_BGRA4444,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_BGRX5551,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_RGBA5551,
+	DRM_FORMAT_BGRA5551,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_RGBA1010102,
+	DRM_FORMAT_BGRA1010102,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_YVU420,
+	DRM_FORMAT_YUV420,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV16,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_P010,
+};
+
+static const u32 primary_overlay_format1[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_RGBA1010102,
+	DRM_FORMAT_BGRA1010102,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_YUV444,
+};
+
+static const u32 cursor_formats[] = {
+	DRM_FORMAT_ARGB8888
+};
+
+static const u64 format_modifier0[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X8),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_8X8),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X8),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_TILE_8X4),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_XMAJOR_8X4),
+	fourcc_mod_vs_norm_code(DRM_FORMAT_MOD_VERISILICON_SUPER_TILED_YMAJOR_4X8),
+	DRM_FORMAT_MOD_INVALID
+};
+
+static const u64 secondary_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+#define FRAC_16_16(mult, div)	 (((mult) << 16) / (div))
+
+static const struct vs_plane_info dc_hw_planes[][PLANE_NUM] = {
+	{
+		/* DC_REV_0 */
+		{
+		.name			= "Primary",
+		.id				= PRIMARY_PLANE_0,
+		.type			= DRM_PLANE_TYPE_PRIMARY,
+		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
+		.formats		= primary_overlay_format0,
+		.num_modifiers	= ARRAY_SIZE(format_modifier0),
+		.modifiers		= format_modifier0,
+		.min_width		= 0,
+		.min_height		= 0,
+		.max_width		= 4096,
+		.max_height		= 4096,
+		.rotation		= DRM_MODE_ROTATE_0 |
+							DRM_MODE_ROTATE_90 |
+							DRM_MODE_ROTATE_180 |
+							DRM_MODE_ROTATE_270 |
+							DRM_MODE_REFLECT_X |
+							DRM_MODE_REFLECT_Y,
+		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+							BIT(DRM_MODE_BLEND_PREMULTI) |
+							BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 0,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name			= "Overlay",
+		.id				= OVERLAY_PLANE_0,
+		.type			= DRM_PLANE_TYPE_OVERLAY,
+		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
+		.formats		= primary_overlay_format0,
+		.num_modifiers	= ARRAY_SIZE(format_modifier0),
+		.modifiers		= format_modifier0,
+		.min_width		= 0,
+		.min_height		= 0,
+		.max_width		= 4096,
+		.max_height		= 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 1,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name			= "Overlay_1",
+		.id				= OVERLAY_PLANE_1,
+		.type			= DRM_PLANE_TYPE_OVERLAY,
+		.num_formats	= ARRAY_SIZE(primary_overlay_format0),
+		.formats		= primary_overlay_format0,
+		.num_modifiers	= ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers		= secondary_format_modifiers,
+		.min_width		= 0,
+		.min_height		= 0,
+		.max_width		= 4096,
+		.max_height		= 4096,
+		.rotation		= 0,
+		.blend_mode		= BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+							BIT(DRM_MODE_BLEND_PREMULTI) |
+							BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 2,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Primary_1",
+		.id				= PRIMARY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 3,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_2",
+		.id				= OVERLAY_PLANE_2,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 4,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_3",
+		.id			= OVERLAY_PLANE_3,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers	 = secondary_format_modifiers,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = 0,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 5,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Cursor",
+		.id				= CURSOR_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+		{
+		.name		 = "Cursor_1",
+		.id				= CURSOR_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+	},
+	{
+		/* DC_REV_1 */
+		{
+		.name		 = "Primary",
+		.id				= PRIMARY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 0,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay",
+		.id				= OVERLAY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 1,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Primary_1",
+		.id				= PRIMARY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 2,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_2",
+		.id				= OVERLAY_PLANE_2,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format0),
+		.formats	 = primary_overlay_format0,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 3,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Cursor",
+		.id				= CURSOR_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+		{
+		.name		 = "Cursor_1",
+		.id				= CURSOR_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+	},
+	{
+		/* DC_REV_2 */
+		{
+		.name		 = "Primary",
+		.id				= PRIMARY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 0,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay",
+		.id				= OVERLAY_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 1,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_1",
+		.id				= OVERLAY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers	 = secondary_format_modifiers,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = 0,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 2,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Primary_1",
+		.id				= PRIMARY_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_PRIMARY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 3,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_2",
+		.id				= OVERLAY_PLANE_2,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(format_modifier0),
+		.modifiers	 = format_modifier0,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = DRM_MODE_ROTATE_0 |
+					   DRM_MODE_ROTATE_90 |
+					   DRM_MODE_ROTATE_180 |
+					   DRM_MODE_ROTATE_270 |
+					   DRM_MODE_REFLECT_X |
+					   DRM_MODE_REFLECT_Y,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = FRAC_16_16(1, 3),
+		.max_scale	 = FRAC_16_16(10, 1),
+		.zpos		 = 4,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Overlay_3",
+		.id				= OVERLAY_PLANE_3,
+		.type		 = DRM_PLANE_TYPE_OVERLAY,
+		.num_formats = ARRAY_SIZE(primary_overlay_format1),
+		.formats	 = primary_overlay_format1,
+		.num_modifiers = ARRAY_SIZE(secondary_format_modifiers),
+		.modifiers	 = secondary_format_modifiers,
+		.min_width	 = 0,
+		.min_height  = 0,
+		.max_width	 = 4096,
+		.max_height  = 4096,
+		.rotation	 = 0,
+		.blend_mode  = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+					   BIT(DRM_MODE_BLEND_PREMULTI) |
+					   BIT(DRM_MODE_BLEND_COVERAGE),
+		.color_encoding = BIT(DRM_COLOR_YCBCR_BT709) |
+						  BIT(DRM_COLOR_YCBCR_BT2020),
+		.degamma_size	= DEGAMMA_SIZE,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 5,
+		.watermark	 = true,
+		.color_mgmt  = true,
+		.roi		 = true,
+		},
+		{
+		.name		 = "Cursor",
+		.id				= CURSOR_PLANE_0,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+		{
+		.name		 = "Cursor_1",
+		.id				= CURSOR_PLANE_1,
+		.type		 = DRM_PLANE_TYPE_CURSOR,
+		.num_formats = ARRAY_SIZE(cursor_formats),
+		.formats	 = cursor_formats,
+		.num_modifiers = 0,
+		.modifiers	 = NULL,
+		.min_width	 = 32,
+		.min_height  = 32,
+		.max_width	 = 64,
+		.max_height  = 64,
+		.rotation	 = 0,
+		.degamma_size = 0,
+		.min_scale	 = DRM_PLANE_NO_SCALING,
+		.max_scale	 = DRM_PLANE_NO_SCALING,
+		.zpos		 = 255,
+		.watermark	 = false,
+		.color_mgmt  = false,
+		.roi		 = false,
+		},
+	},
+};
+
+static const struct vs_dc_info dc_info[] = {
+	{
+		/* DC_REV_0 */
+		.name			= "DC8200",
+		.panel_num		= 2,
+		.plane_num		= 8,
+		.planes			= dc_hw_planes[DC_REV_0],
+		.layer_num		= 6,
+		.max_bpc		= 10,
+		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
+						  DRM_COLOR_FORMAT_YCBCR444 |
+						  DRM_COLOR_FORMAT_YCBCR422 |
+						  DRM_COLOR_FORMAT_YCBCR420,
+		.gamma_size		= GAMMA_EX_SIZE,
+		.gamma_bits		= 12,
+		.pitch_alignment	= 128,
+		.pipe_sync		= false,
+		.background		= true,
+		.panel_sync		= true,
+		.cap_dec		= true,
+	},
+	{
+		/* DC_REV_1 */
+		.name			= "DC8200",
+		.panel_num		= 2,
+		.plane_num		= 6,
+		.planes			= dc_hw_planes[DC_REV_1],
+		.layer_num		= 4,
+		.max_bpc		= 10,
+		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
+						  DRM_COLOR_FORMAT_YCBCR444 |
+						  DRM_COLOR_FORMAT_YCBCR422 |
+						  DRM_COLOR_FORMAT_YCBCR420,
+		.gamma_size		= GAMMA_EX_SIZE,
+		.gamma_bits		= 12,
+		.pitch_alignment	= 128,
+		.pipe_sync		= false,
+		.background		= true,
+		.panel_sync		= true,
+		.cap_dec		= true,
+	},
+	{
+		/* DC_REV_2 */
+		.name			= "DC8200",
+		.panel_num		= 2,
+		.plane_num		= 8,
+		.planes			= dc_hw_planes[DC_REV_2],
+		.layer_num		= 6,
+		.max_bpc		= 10,
+		.color_formats	= DRM_COLOR_FORMAT_RGB444 |
+						  DRM_COLOR_FORMAT_YCBCR444 |
+						  DRM_COLOR_FORMAT_YCBCR422 |
+						  DRM_COLOR_FORMAT_YCBCR420,
+		.gamma_size		= GAMMA_EX_SIZE,
+		.gamma_bits		= 12,
+		.pitch_alignment	= 128,
+		.pipe_sync		= false,
+		.background		= true,
+		.panel_sync		= true,
+		.cap_dec		= false,
+	},
+};
+
+static const struct dc_hw_funcs hw_func;
+
+static inline u32 hi_read(struct dc_hw *hw, u32 reg)
+{
+	return readl(hw->hi_base + reg);
+}
+
+static inline void hi_write(struct dc_hw *hw, u32 reg, u32 value)
+{
+	writel(value, hw->hi_base + reg);
+}
+
+static inline void dc_write(struct dc_hw *hw, u32 reg, u32 value)
+{
+	writel(value, hw->reg_base + reg - DC_REG_BASE);
+}
+
+static inline u32 dc_read(struct dc_hw *hw, u32 reg)
+{
+	u32 value = readl(hw->reg_base + reg - DC_REG_BASE);
+
+	return value;
+}
+
+static inline void dc_set_clear(struct dc_hw *hw, u32 reg, u32 set, u32 clear)
+{
+	u32 value = dc_read(hw, reg);
+
+	value &= ~clear;
+	value |= set;
+	dc_write(hw, reg, value);
+}
+
+static void load_default_filter(struct dc_hw *hw,
+				const struct dc_hw_plane_reg *reg, u32 offset)
+{
+	u8 i;
+
+	dc_write(hw, reg->scale_config + offset, 0x33);
+	dc_write(hw, reg->init_offset + offset, 0x80008000);
+	dc_write(hw, reg->h_filter_coef_index + offset, 0x00);
+	for (i = 0; i < H_COEF_SIZE; i++)
+		dc_write(hw, reg->h_filter_coef_data + offset, horkernel[i]);
+
+	dc_write(hw, reg->v_filter_coef_index + offset, 0x00);
+	for (i = 0; i < V_COEF_SIZE; i++)
+		dc_write(hw, reg->v_filter_coef_data + offset, verkernel[i]);
+}
+
+static void load_rgb_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
+			    u32 offset, u16 *table)
+{
+	dc_write(hw, reg->rgb_to_rgb_coef0 + offset, table[0] | (table[1] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef1 + offset, table[2] | (table[3] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef2 + offset, table[4] | (table[5] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef3 + offset, table[6] | (table[7] << 16));
+	dc_write(hw, reg->rgb_to_rgb_coef4 + offset, table[8]);
+}
+
+static void load_yuv_to_rgb(struct dc_hw *hw, const struct dc_hw_plane_reg *reg,
+			    u32 offset, s32 *table)
+{
+	dc_write(hw, reg->yuv_to_rgb_coef0 + offset,
+		 (0xFFFF & table[0]) | (table[1] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef1 + offset,
+		 (0xFFFF & table[2]) | (table[3] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef2 + offset,
+		 (0xFFFF & table[4]) | (table[5] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef3 + offset,
+		 (0xFFFF & table[6]) | (table[7] << 16));
+	dc_write(hw, reg->yuv_to_rgb_coef4 + offset, table[8]);
+	dc_write(hw, reg->yuv_to_rgb_coefd0 + offset, table[9]);
+	dc_write(hw, reg->yuv_to_rgb_coefd1 + offset, table[10]);
+	dc_write(hw, reg->yuv_to_rgb_coefd2 + offset, table[11]);
+	dc_write(hw, reg->y_clamp_bound + offset, table[12] | (table[13] << 16));
+	dc_write(hw, reg->uv_clamp_bound + offset, table[14] | (table[15] << 16));
+}
+
+static void load_rgb_to_yuv(struct dc_hw *hw, u32 offset, s16 *table)
+{
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF0 + offset,
+		 table[0] | (table[1] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF1 + offset,
+		 table[2] | (table[3] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF2 + offset,
+		 table[4] | (table[5] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF3 + offset,
+		 table[6] | (table[7] << 16));
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEF4 + offset, table[8]);
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD0 + offset, table[9]);
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD1 + offset, table[10]);
+	dc_write(hw, DC_DISPLAY_RGBTOYUV_COEFD2 + offset, table[11]);
+}
+
+static bool is_rgb(enum dc_hw_color_format format)
+{
+	switch (format) {
+	case FORMAT_X4R4G4B4:
+	case FORMAT_A4R4G4B4:
+	case FORMAT_X1R5G5B5:
+	case FORMAT_A1R5G5B5:
+	case FORMAT_R5G6B5:
+	case FORMAT_X8R8G8B8:
+	case FORMAT_A8R8G8B8:
+	case FORMAT_A2R10G10B10:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void load_degamma_table(struct dc_hw *hw,
+			       const struct dc_hw_plane_reg *reg,
+			       u32 offset, u16 *table)
+{
+	u16 i;
+	u32 value;
+
+	dc_write(hw, reg->degamma_index + offset, 0);
+
+	for (i = 0; i < DEGAMMA_SIZE; i++) {
+		value = table[i] | (table[i] << 16);
+		dc_write(hw, reg->degamma_data + offset, value);
+		dc_write(hw, reg->degamma_ex_data + offset, table[i]);
+	}
+}
+
+static u32 get_addr_offset(u32 id)
+{
+	u32 offset = 0;
+
+	switch (id) {
+	case PRIMARY_PLANE_1:
+	case OVERLAY_PLANE_1:
+		offset = 0x04;
+		break;
+	case OVERLAY_PLANE_2:
+		offset = 0x08;
+		break;
+	case OVERLAY_PLANE_3:
+		offset = 0x0C;
+		break;
+	default:
+		break;
+	}
+
+	return offset;
+}
+
+int dc_hw_init(struct dc_hw *hw)
+{
+	u8 i, id, panel_num, layer_num;
+	u32 offset;
+	u32 revision = hi_read(hw, DC_HW_REVISION);
+	u32 cid = hi_read(hw, DC_HW_CHIP_CID);
+	const struct dc_hw_plane_reg *reg;
+
+	switch (revision) {
+	case 0x5720:
+		hw->rev = DC_REV_0;
+		break;
+	case 0x5721:
+		switch (cid) {
+		case 0x30B:
+			hw->rev = DC_REV_1;
+			break;
+		case 0x310:
+			hw->rev = DC_REV_2;
+			break;
+		default:
+			hw->rev = DC_REV_0;
+			break;
+		}
+		break;
+	default:
+		return -ENXIO;
+	}
+
+	hw->info = (struct vs_dc_info *)&dc_info[hw->rev];
+	hw->func = (struct dc_hw_funcs *)&hw_func;
+
+	layer_num = hw->info->layer_num;
+	for (i = 0; i < layer_num; i++) {
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+			reg = &dc_plane_reg[0];
+		else
+			reg = &dc_plane_reg[1];
+
+		load_default_filter(hw, reg, offset);
+		load_rgb_to_rgb(hw, reg, offset, RGB2RGB);
+	}
+
+	panel_num = hw->info->panel_num;
+	for (i = 0; i < panel_num; i++) {
+		offset = i << 2;
+
+		load_rgb_to_yuv(hw, offset, RGB2YUV);
+		dc_write(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0x111);
+
+		offset = i ? DC_CURSOR_OFFSET : 0;
+		dc_write(hw, DC_CURSOR_BACKGROUND + offset, 0x00FFFFFF);
+		dc_write(hw, DC_CURSOR_FOREGROUND + offset, 0x00AAAAAA);
+	}
+
+	return 0;
+}
+
+void dc_hw_deinit(struct dc_hw *hw)
+{
+	/* Nothing to do */
+}
+
+void dc_hw_update_plane(struct dc_hw *hw, u8 id,
+			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
+			struct dc_hw_position *pos, struct dc_hw_blend *blend)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		if (fb) {
+			if (!fb->enable)
+				plane->fb.enable = false;
+			else
+				memcpy(&plane->fb, fb,
+				       sizeof(*fb) - sizeof(fb->dirty));
+			plane->fb.dirty = true;
+		}
+		if (scale) {
+			memcpy(&plane->scale, scale,
+			       sizeof(*scale) - sizeof(scale->dirty));
+			plane->scale.dirty = true;
+		}
+		if (pos) {
+			memcpy(&plane->pos, pos,
+			       sizeof(*pos) - sizeof(pos->dirty));
+			plane->pos.dirty = true;
+		}
+		if (blend) {
+			memcpy(&plane->blend, blend,
+			       sizeof(*blend) - sizeof(blend->dirty));
+			plane->blend.dirty = true;
+		}
+	}
+}
+
+void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		if (hw->info->planes[id].degamma_size) {
+			plane->degamma.mode = mode;
+			plane->degamma.dirty = true;
+		} else {
+			plane->degamma.dirty = false;
+		}
+	}
+}
+
+void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		memcpy(&plane->roi, roi, sizeof(*roi) - sizeof(roi->dirty));
+		plane->roi.dirty = true;
+	}
+}
+
+void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
+			   struct dc_hw_colorkey *colorkey)
+{
+	struct dc_hw_plane *plane = &hw->plane[id];
+
+	if (plane) {
+		memcpy(&plane->colorkey, colorkey,
+		       sizeof(*colorkey) - sizeof(colorkey->dirty));
+		plane->colorkey.dirty = true;
+	}
+}
+
+void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos)
+{
+	memcpy(&hw->qos, qos, sizeof(*qos) - sizeof(qos->dirty));
+	hw->qos.dirty = true;
+}
+
+void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor)
+{
+	memcpy(&hw->cursor[id], cursor, sizeof(*cursor) - sizeof(cursor->dirty));
+	hw->cursor[id].dirty = true;
+}
+
+void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
+			u16 r, u16 g, u16 b)
+{
+	if (index >= hw->info->gamma_size)
+		return;
+
+	hw->gamma[id].gamma[index][0] = r;
+	hw->gamma[id].gamma[index][1] = g;
+	hw->gamma[id].gamma[index][2] = b;
+	hw->gamma[id].dirty = true;
+}
+
+void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable)
+{
+	hw->gamma[id].enable = enable;
+	hw->gamma[id].dirty = true;
+}
+
+void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display)
+{
+	u8 id = display->id;
+
+	memcpy(&hw->display[id], display, sizeof(*display));
+
+	hw->func->display(hw, display);
+}
+
+void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable)
+{
+	if (enable)
+		hi_write(hw, AQ_INTR_ENBL, 0xFFFFFFFF);
+	else
+		hi_write(hw, AQ_INTR_ENBL, 0);
+}
+
+u32 dc_hw_get_interrupt(struct dc_hw *hw)
+{
+	return hi_read(hw, AQ_INTR_ACKNOWLEDGE);
+}
+
+bool dc_hw_check_underflow(struct dc_hw *hw)
+{
+	return dc_read(hw, DC_FRAMEBUFFER_CONFIG) & BIT(5);
+}
+
+void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable)
+{
+	u32 i, offset;
+	u8 id, layer_num = hw->info->layer_num;
+	u8 panel_num = hw->info->panel_num;
+
+	for (i = 0; i < layer_num; i++) {
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (enable) {
+			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, BIT(12), 0);
+			else
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, BIT(31), 0);
+		} else {
+			if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1)
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset, 0, BIT(12));
+			else
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset, 0, BIT(31));
+		}
+	}
+
+	for (i = 0; i < panel_num; i++) {
+		offset = i << 2;
+		if (enable)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, 0, BIT(0));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG_EX + offset, BIT(0), 0);
+	}
+}
+
+void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id)
+{
+	if (out <= OUT_DP)
+		hw->out[id] = out;
+}
+
+static void gamma_ex_commit(struct dc_hw *hw)
+{
+	u8 panel_num = hw->info->panel_num;
+	u16 i, j;
+	u32 value;
+
+	for (j = 0; j < panel_num; j++) {
+		if (hw->gamma[j].dirty) {
+			if (hw->gamma[j].enable) {
+				dc_write(hw, DC_DISPLAY_GAMMA_EX_INDEX + (j << 2), 0x00);
+				for (i = 0; i < GAMMA_EX_SIZE; i++) {
+					value = hw->gamma[j].gamma[i][2] |
+						(hw->gamma[j].gamma[i][1] << 12);
+					dc_write(hw, DC_DISPLAY_GAMMA_EX_DATA + (j << 2), value);
+					dc_write(hw, DC_DISPLAY_GAMMA_EX_ONE_DATA + (j << 2),
+						 hw->gamma[j].gamma[i][0]);
+				}
+				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
+					     BIT(13), 0);
+			} else {
+				dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + (j << 2),
+					     0, BIT(13));
+			}
+			hw->gamma[j].dirty = false;
+		}
+	}
+}
+
+static void plane_commit(struct dc_hw *hw)
+{
+	struct dc_hw_plane *plane;
+	const struct dc_hw_plane_reg *reg;
+	bool primary = false;
+	u8 id, layer_num = hw->info->layer_num;
+	u32 i, offset;
+
+	for (i = 0; i < layer_num; i++) {
+		plane = &hw->plane[i];
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
+			reg = &dc_plane_reg[0];
+			primary = true;
+		} else {
+			reg = &dc_plane_reg[1];
+			primary = false;
+		}
+
+		if (plane->fb.dirty) {
+			if (plane->fb.enable) {
+				dc_write(hw, reg->y_address + offset,
+					 plane->fb.y_address);
+				dc_write(hw, reg->u_address + offset,
+					 plane->fb.u_address);
+				dc_write(hw, reg->v_address + offset,
+					 plane->fb.v_address);
+				dc_write(hw, reg->y_stride + offset,
+					 plane->fb.y_stride);
+				dc_write(hw, reg->u_stride + offset,
+					 plane->fb.u_stride);
+				dc_write(hw, reg->v_stride + offset,
+					 plane->fb.v_stride);
+				dc_write(hw, reg->size + offset,
+					 plane->fb.width |
+					 (plane->fb.height << 15));
+				dc_write(hw, reg->water_mark + offset,
+					 plane->fb.water_mark);
+
+				if (plane->fb.clear_enable)
+					dc_write(hw, reg->clear_value + offset,
+						 plane->fb.clear_value);
+			}
+
+			if (primary) {
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
+					     (plane->fb.format << 26) |
+					     (plane->fb.uv_swizzle << 25) |
+					     (plane->fb.swizzle << 23) |
+					     (plane->fb.tile_mode << 17) |
+					     (plane->fb.yuv_color_space << 14) |
+					     (plane->fb.rotation << 11) |
+					     (plane->fb.clear_enable << 8),
+					     (0x1F << 26) |
+					     BIT(25) |
+					     (0x03 << 23) |
+					     (0x1F << 17) |
+					     (0x07 << 14) |
+					     (0x07 << 11) |
+					     BIT(8));
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+					     (plane->fb.dec_enable << 1) |
+					     (plane->fb.enable << 13) |
+					     (plane->fb.zpos << 16) |
+					     (plane->fb.display_id << 19),
+					     BIT(1) | BIT(13) | (0x07 << 16) | BIT(19));
+			} else {
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+					     (plane->fb.dec_enable << 27) |
+					     (plane->fb.clear_enable << 25) |
+					     (plane->fb.enable << 24) |
+					     (plane->fb.format << 16) |
+					     (plane->fb.uv_swizzle << 15) |
+					     (plane->fb.swizzle << 13) |
+					     (plane->fb.tile_mode << 8) |
+					     (plane->fb.yuv_color_space << 5) |
+					     (plane->fb.rotation << 2),
+					     BIT(27) |
+					     BIT(25) |
+					     BIT(24) |
+					     (0x1F << 16) |
+					     BIT(15) |
+					     (0x03 << 13) |
+					     (0x1F << 8) |
+					     (0x07 << 5) |
+					     (0x07 << 2));
+				dc_set_clear(hw, DC_OVERLAY_CONFIG_EX + offset,
+					     plane->fb.zpos | (plane->fb.display_id << 3),
+					     0x07 | BIT(3));
+			}
+			plane->fb.dirty = false;
+		}
+
+		if (plane->scale.dirty) {
+			if (plane->scale.enable) {
+				dc_write(hw, reg->scale_factor_x + offset,
+					 plane->scale.scale_factor_x);
+				dc_write(hw, reg->scale_factor_y + offset,
+					 plane->scale.scale_factor_y);
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG + offset,
+						     BIT(22), 0);
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_SCALE_CONFIG + offset,
+						     BIT(8), 0);
+			} else {
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG + offset,
+						     0, BIT(22));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_SCALE_CONFIG + offset,
+						     0, BIT(8));
+			}
+			plane->scale.dirty = false;
+		}
+
+		if (plane->pos.dirty) {
+			dc_write(hw, reg->top_left + offset,
+				 plane->pos.start_x |
+				 (plane->pos.start_y << 15));
+			dc_write(hw, reg->bottom_right + offset,
+				 plane->pos.end_x |
+				 (plane->pos.end_y << 15));
+			plane->pos.dirty = false;
+		}
+
+		if (plane->blend.dirty) {
+			dc_write(hw, reg->src_global_color + offset,
+				 plane->blend.alpha << 24);
+			dc_write(hw, reg->dst_global_color + offset,
+				 plane->blend.alpha << 24);
+			switch (plane->blend.blend_mode) {
+			case BLEND_PREMULTI:
+				dc_write(hw, reg->blend_config + offset, 0x3450);
+				break;
+			case BLEND_COVERAGE:
+				dc_write(hw, reg->blend_config + offset, 0x3950);
+				break;
+			case BLEND_PIXEL_NONE:
+				dc_write(hw, reg->blend_config + offset, 0x3548);
+				break;
+			default:
+				break;
+			}
+			plane->blend.dirty = false;
+		}
+
+		if (plane->colorkey.dirty) {
+			dc_write(hw, reg->color_key + offset, plane->colorkey.colorkey);
+			dc_write(hw, reg->color_key_high + offset,
+				 plane->colorkey.colorkey_high);
+
+			if (primary)
+				dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG + offset,
+					     plane->colorkey.transparency << 9, 0x03 << 9);
+			else
+				dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+					     plane->colorkey.transparency, 0x03);
+
+			plane->colorkey.dirty = false;
+		}
+
+		if (plane->roi.dirty) {
+			if (plane->roi.enable) {
+				dc_write(hw, reg->roi_origin + offset,
+					 plane->roi.x | (plane->roi.y << 16));
+				dc_write(hw, reg->roi_size + offset,
+					 plane->roi.width | (plane->roi.height << 16));
+				if (primary)
+					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(0), 0);
+				else
+					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+						     BIT(22), 0);
+			} else {
+				if (primary)
+					dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     0, BIT(0));
+				else
+					dc_set_clear(hw, DC_OVERLAY_CONFIG + offset,
+						     0, BIT(22));
+			}
+			plane->roi.dirty = false;
+		}
+	}
+}
+
+static void plane_ex_commit(struct dc_hw *hw)
+{
+	struct dc_hw_plane *plane;
+	const struct dc_hw_plane_reg *reg;
+	bool primary = false;
+	u8 id, layer_num = hw->info->layer_num;
+	u32 i, offset;
+
+	for (i = 0; i < layer_num; i++) {
+		plane = &hw->plane[i];
+		id = hw->info->planes[i].id;
+		offset = get_addr_offset(id);
+		if (id == PRIMARY_PLANE_0 || id == PRIMARY_PLANE_1) {
+			reg = &dc_plane_reg[0];
+			primary = true;
+		} else {
+			reg = &dc_plane_reg[1];
+			primary = false;
+		}
+
+		if (plane->fb.dirty) {
+			if (is_rgb(plane->fb.format)) {
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(6), BIT(8));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(29), BIT(30));
+			} else {
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(8), BIT(6));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(30), BIT(29));
+				switch (plane->fb.yuv_color_space) {
+				case COLOR_SPACE_601:
+					load_yuv_to_rgb(hw, reg, offset, YUV601_2RGB);
+					break;
+				case COLOR_SPACE_709:
+					load_yuv_to_rgb(hw, reg, offset, YUV709_2RGB);
+					break;
+				case COLOR_SPACE_2020:
+					load_yuv_to_rgb(hw, reg, offset, YUV2020_2RGB);
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		if (plane->degamma.dirty) {
+			switch (plane->degamma.mode) {
+			case VS_DEGAMMA_DISABLE:
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     0, BIT(5));
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     0, BIT(28));
+				break;
+			case VS_DEGAMMA_BT709:
+				load_degamma_table(hw, reg, offset, DEGAMMA_709);
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(5), 0);
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(28), 0);
+				break;
+			case VS_DEGAMMA_BT2020:
+				load_degamma_table(hw, reg, offset, DEGAMMA_2020);
+				if (primary)
+					dc_set_clear(hw,
+						     DC_FRAMEBUFFER_CONFIG_EX + offset,
+						     BIT(5), 0);
+				else
+					dc_set_clear(hw,
+						     DC_OVERLAY_CONFIG + offset,
+						     BIT(28), 0);
+				break;
+			default:
+				break;
+			}
+			plane->degamma.dirty = false;
+		}
+	}
+	plane_commit(hw);
+}
+
+static void setup_display(struct dc_hw *hw, struct dc_hw_display *display)
+{
+	u8 id = display->id;
+	u32 dpi_cfg, offset = id << 2;
+
+	if (hw->display[id].enable) {
+		switch (display->bus_format) {
+		case MEDIA_BUS_FMT_RGB565_1X16:
+			dpi_cfg = 0;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			dpi_cfg = 3;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+			dpi_cfg = 4;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			dpi_cfg = 5;
+			break;
+		case MEDIA_BUS_FMT_RGB101010_1X30:
+			dpi_cfg = 6;
+			break;
+		default:
+			dpi_cfg = 5;
+			break;
+		}
+		dc_write(hw, DC_DISPLAY_DPI_CONFIG + offset, dpi_cfg);
+
+		if (id == 0)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
+
+		dc_write(hw, DC_DISPLAY_H + offset, hw->display[id].h_active |
+			 (hw->display[id].h_total << 16));
+		dc_write(hw, DC_DISPLAY_H_SYNC + offset,
+			 hw->display[id].h_sync_start |
+			 (hw->display[id].h_sync_end << 15) |
+			 (hw->display[id].h_sync_polarity ? 0 : BIT(31)) |
+			 BIT(30));
+		dc_write(hw, DC_DISPLAY_V + offset, hw->display[id].v_active |
+				(hw->display[id].v_total << 16));
+		dc_write(hw, DC_DISPLAY_V_SYNC + offset,
+			 hw->display[id].v_sync_start |
+			 (hw->display[id].v_sync_end << 15) |
+			 (hw->display[id].v_sync_polarity ? 0 : BIT(31)) |
+			 BIT(30));
+
+		if (hw->info->pipe_sync)
+			dc_set_clear(hw, DC_FRAMEBUFFER_CONFIG_EX,
+				     0, BIT(3) | BIT(4));
+
+		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(12), 0);
+		if (id == 0)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(0), BIT(3));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, BIT(1), BIT(3));
+	} else {
+		dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(12));
+		if (id == 0)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(0) | BIT(2));
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_START, 0, BIT(1) | BIT(2));
+	}
+}
+
+static void setup_display_ex(struct dc_hw *hw, struct dc_hw_display *display)
+{
+	u8 id = display->id;
+	u32 dp_cfg, offset = id << 2;
+	bool is_yuv = false;
+
+	if (hw->display[id].enable && hw->out[id] == OUT_DP) {
+		switch (display->bus_format) {
+		case MEDIA_BUS_FMT_RGB565_1X16:
+			dp_cfg = 0;
+			break;
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			dp_cfg = 1;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			dp_cfg = 2;
+			break;
+		case MEDIA_BUS_FMT_RGB101010_1X30:
+			dp_cfg = 3;
+			break;
+		case MEDIA_BUS_FMT_UYVY8_1X16:
+			dp_cfg = 2 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_YUV8_1X24:
+			dp_cfg = 4 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_UYVY10_1X20:
+			dp_cfg = 8 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_YUV10_1X30:
+			dp_cfg = 10 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+			dp_cfg = 12 << 4;
+			is_yuv = true;
+			break;
+		case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+			dp_cfg = 13 << 4;
+			is_yuv = true;
+			break;
+		default:
+			dp_cfg = 2;
+			break;
+		}
+		if (is_yuv)
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, BIT(16), 0);
+		else
+			dc_set_clear(hw, DC_DISPLAY_PANEL_CONFIG + offset, 0, BIT(16));
+		dc_write(hw, DC_DISPLAY_DP_CONFIG + offset, dp_cfg | BIT(3));
+	}
+
+	if (hw->out[id] == OUT_DPI)
+		dc_set_clear(hw, DC_DISPLAY_DP_CONFIG + offset, 0, BIT(3));
+
+	setup_display(hw, display);
+}
+
+static const struct dc_hw_funcs hw_func = {
+	.gamma = &gamma_ex_commit,
+	.plane = &plane_ex_commit,
+	.display = setup_display_ex,
+};
+
+void dc_hw_commit(struct dc_hw *hw)
+{
+	u32 i, offset = 0;
+	u8 plane_num = hw->info->plane_num;
+	u8 layer_num = hw->info->layer_num;
+	u8 cursor_num = plane_num - layer_num;
+
+	hw->func->gamma(hw);
+	hw->func->plane(hw);
+
+	for (i = 0; i < cursor_num; i++) {
+		if (hw->cursor[i].dirty) {
+			offset = hw->cursor[i].display_id ? DC_CURSOR_OFFSET : 0;
+			if (hw->cursor[i].enable) {
+				dc_write(hw, DC_CURSOR_ADDRESS + offset,
+					 hw->cursor[i].address);
+				dc_write(hw, DC_CURSOR_LOCATION + offset, hw->cursor[i].x |
+					 (hw->cursor[i].y << 16));
+				dc_set_clear(hw, DC_CURSOR_CONFIG + offset,
+					     (hw->cursor[i].hot_x << 16) |
+					     (hw->cursor[i].hot_y << 8) |
+					     (hw->cursor[i].size << 5) |
+					     BIT(3) | BIT(2) | 0x02,
+					     (0xFF << 16) |
+					     (0xFF << 8) |
+					     (0x07 << 5) | 0x1F);
+			} else {
+				dc_set_clear(hw, DC_CURSOR_CONFIG + offset, BIT(3), 0x03);
+			}
+			hw->cursor[i].dirty = false;
+		}
+	}
+
+	if (hw->qos.dirty) {
+		dc_set_clear(hw, DC_QOS_CONFIG, (hw->qos.high_value << 4) |
+					 hw->qos.low_value, 0xFF);
+		hw->qos.dirty = false;
+	}
+}
+
diff --git a/drivers/gpu/drm/verisilicon/vs_dc_hw.h b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
new file mode 100644
index 000000000..9a1d767ae
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_dc_hw.h
@@ -0,0 +1,492 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_DC_HW_H__
+#define __VS_DC_HW_H__
+
+#define AQ_INTR_ACKNOWLEDGE				0x0010
+#define AQ_INTR_ENBL					0x0014
+#define DC_HW_REVISION					0x0024
+#define DC_HW_CHIP_CID					0x0030
+
+#define DC_REG_BASE						0x0800
+#define DC_REG_RANGE					0x2000
+#define DC_SEC_REG_OFFSET				0x100000
+
+#define DC_FRAMEBUFFER_CONFIG			0x1518
+#define DC_FRAMEBUFFER_CONFIG_EX		0x1CC0
+#define DC_FRAMEBUFFER_SCALE_CONFIG		0x1520
+#define DC_FRAMEBUFFER_TOP_LEFT			0x24D8
+#define DC_FRAMEBUFFER_BOTTOM_RIGHT		0x24E0
+#define DC_FRAMEBUFFER_ADDRESS			0x1400
+#define DC_FRAMEBUFFER_U_ADDRESS		0x1530
+#define DC_FRAMEBUFFER_V_ADDRESS		0x1538
+#define DC_FRAMEBUFFER_STRIDE			0x1408
+#define DC_FRAMEBUFFER_U_STRIDE			0x1800
+#define DC_FRAMEBUFFER_V_STRIDE			0x1808
+#define DC_FRAMEBUFFER_SIZE				0x1810
+#define DC_FRAMEBUFFER_SCALE_FACTOR_X		0x1828
+#define DC_FRAMEBUFFER_SCALE_FACTOR_Y		0x1830
+#define DC_FRAMEBUFFER_H_FILTER_COEF_INDEX	0x1838
+#define DC_FRAMEBUFFER_H_FILTER_COEF_DATA	0x1A00
+#define DC_FRAMEBUFFER_V_FILTER_COEF_INDEX	0x1A08
+#define DC_FRAMEBUFFER_V_FILTER_COEF_DATA	0x1A10
+#define DC_FRAMEBUFFER_INIT_OFFSET			0x1A20
+#define DC_FRAMEBUFFER_COLOR_KEY			0x1508
+#define DC_FRAMEBUFFER_COLOR_KEY_HIGH		0x1510
+#define DC_FRAMEBUFFER_CLEAR_VALUE			0x1A18
+#define DC_FRAMEBUFFER_COLOR_TABLE_INDEX	0x1818
+#define DC_FRAMEBUFFER_COLOR_TABLE_DATA		0x1820
+#define DC_FRAMEBUFFER_BG_COLOR				0x1528
+#define DC_FRAMEBUFFER_ROI_ORIGIN			0x1CB0
+#define DC_FRAMEBUFFER_ROI_SIZE				0x1CB8
+#define DC_FRAMEBUFFER_WATER_MARK			0x1CE8
+#define DC_FRAMEBUFFER_DEGAMMA_INDEX		0x1D88
+#define DC_FRAMEBUFFER_DEGAMMA_DATA			0x1D90
+#define DC_FRAMEBUFFER_DEGAMMA_EX_DATA		0x1D98
+#define DC_FRAMEBUFFER_YUVTORGB_COEF0		0x1DA0
+#define DC_FRAMEBUFFER_YUVTORGB_COEF1		0x1DA8
+#define DC_FRAMEBUFFER_YUVTORGB_COEF2		0x1DB0
+#define DC_FRAMEBUFFER_YUVTORGB_COEF3		0x1DB8
+#define DC_FRAMEBUFFER_YUVTORGB_COEF4		0x1E00
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD0		0x1E08
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD1		0x1E10
+#define DC_FRAMEBUFFER_YUVTORGB_COEFD2		0x1E18
+#define DC_FRAMEBUFFER_Y_CLAMP_BOUND		0x1E88
+#define DC_FRAMEBUFFER_UV_CLAMP_BOUND		0x1E90
+#define DC_FRAMEBUFFER_RGBTORGB_COEF0		0x1E20
+#define DC_FRAMEBUFFER_RGBTORGB_COEF1		0x1E28
+#define DC_FRAMEBUFFER_RGBTORGB_COEF2		0x1E30
+#define DC_FRAMEBUFFER_RGBTORGB_COEF3		0x1E38
+#define DC_FRAMEBUFFER_RGBTORGB_COEF4		0x1E40
+#define DC_FRAMEBUFFER_BLEND_CONFIG			0x2510
+#define DC_FRAMEBUFFER_SRC_GLOBAL_COLOR		0x2500
+#define DC_FRAMEBUFFER_DST_GLOBAL_COLOR		0x2508
+
+#define DC_OVERLAY_CONFIG					0x1540
+#define DC_OVERLAY_CONFIG_EX				0x2540
+#define DC_OVERLAY_SCALE_CONFIG				0x1C00
+#define DC_OVERLAY_BLEND_CONFIG				0x1580
+#define DC_OVERLAY_TOP_LEFT					0x1640
+#define DC_OVERLAY_BOTTOM_RIGHT				0x1680
+#define DC_OVERLAY_ADDRESS					0x15C0
+#define DC_OVERLAY_U_ADDRESS				0x1840
+#define DC_OVERLAY_V_ADDRESS				0x1880
+#define DC_OVERLAY_STRIDE					0x1600
+#define DC_OVERLAY_U_STRIDE					0x18C0
+#define DC_OVERLAY_V_STRIDE					0x1900
+#define DC_OVERLAY_SIZE						0x17C0
+#define DC_OVERLAY_SCALE_FACTOR_X			0x1A40
+#define DC_OVERLAY_SCALE_FACTOR_Y			0x1A80
+#define DC_OVERLAY_H_FILTER_COEF_INDEX		0x1AC0
+#define DC_OVERLAY_H_FILTER_COEF_DATA		0x1B00
+#define DC_OVERLAY_V_FILTER_COEF_INDEX		0x1B40
+#define DC_OVERLAY_V_FILTER_COEF_DATA		0x1B80
+#define DC_OVERLAY_INIT_OFFSET				0x1BC0
+#define DC_OVERLAY_COLOR_KEY				0x1740
+#define DC_OVERLAY_COLOR_KEY_HIGH			0x1780
+#define DC_OVERLAY_CLEAR_VALUE				0x1940
+#define DC_OVERLAY_COLOR_TABLE_INDEX		0x1980
+#define DC_OVERLAY_COLOR_TABLE_DATA			0x19C0
+#define DC_OVERLAY_SRC_GLOBAL_COLOR			0x16C0
+#define DC_OVERLAY_DST_GLOBAL_COLOR			0x1700
+#define DC_OVERLAY_ROI_ORIGIN				0x1D00
+#define DC_OVERLAY_ROI_SIZE					0x1D40
+#define DC_OVERLAY_WATER_MARK				0x1DC0
+#define DC_OVERLAY_DEGAMMA_INDEX			0x2200
+#define DC_OVERLAY_DEGAMMA_DATA				0x2240
+#define DC_OVERLAY_DEGAMMA_EX_DATA			0x2280
+#define DC_OVERLAY_YUVTORGB_COEF0			0x1EC0
+#define DC_OVERLAY_YUVTORGB_COEF1			0x1F00
+#define DC_OVERLAY_YUVTORGB_COEF2			0x1F40
+#define DC_OVERLAY_YUVTORGB_COEF3			0x1F80
+#define DC_OVERLAY_YUVTORGB_COEF4			0x1FC0
+#define DC_OVERLAY_YUVTORGB_COEFD0			0x2000
+#define DC_OVERLAY_YUVTORGB_COEFD1			0x2040
+#define DC_OVERLAY_YUVTORGB_COEFD2			0x2080
+#define DC_OVERLAY_Y_CLAMP_BOUND			0x22C0
+#define DC_OVERLAY_UV_CLAMP_BOUND			0x2300
+#define DC_OVERLAY_RGBTORGB_COEF0			0x20C0
+#define DC_OVERLAY_RGBTORGB_COEF1			0x2100
+#define DC_OVERLAY_RGBTORGB_COEF2			0x2140
+#define DC_OVERLAY_RGBTORGB_COEF3			0x2180
+#define DC_OVERLAY_RGBTORGB_COEF4			0x21C0
+
+#define DC_CURSOR_CONFIG					0x1468
+#define DC_CURSOR_ADDRESS					0x146C
+#define DC_CURSOR_LOCATION					0x1470
+#define DC_CURSOR_BACKGROUND				0x1474
+#define DC_CURSOR_FOREGROUND				0x1478
+#define DC_CURSOR_CLK_GATING				0x1484
+#define DC_CURSOR_CONFIG_EX					0x24E8
+#define DC_CURSOR_OFFSET					0x1080
+
+#define DC_DISPLAY_DITHER_CONFIG		0x1410
+#define DC_DISPLAY_PANEL_CONFIG			0x1418
+#define DC_DISPLAY_PANEL_CONFIG_EX		0x2518
+#define DC_DISPLAY_DITHER_TABLE_LOW		0x1420
+#define DC_DISPLAY_DITHER_TABLE_HIGH	0x1428
+#define DC_DISPLAY_H					0x1430
+#define DC_DISPLAY_H_SYNC				0x1438
+#define DC_DISPLAY_V					0x1440
+#define DC_DISPLAY_V_SYNC				0x1448
+#define DC_DISPLAY_CURRENT_LOCATION		0x1450
+#define DC_DISPLAY_GAMMA_INDEX			0x1458
+#define DC_DISPLAY_GAMMA_DATA			0x1460
+#define DC_DISPLAY_INT					0x147C
+#define DC_DISPLAY_INT_ENABLE			0x1480
+#define DC_DISPLAY_DBI_CONFIG			0x1488
+#define DC_DISPLAY_GENERAL_CONFIG		0x14B0
+#define DC_DISPLAY_DPI_CONFIG			0x14B8
+#define DC_DISPLAY_PANEL_START			0x1CCC
+#define DC_DISPLAY_DEBUG_COUNTER_SELECT		0x14D0
+#define DC_DISPLAY_DEBUG_COUNTER_VALUE		0x14D8
+#define DC_DISPLAY_DP_CONFIG				0x1CD0
+#define DC_DISPLAY_GAMMA_EX_INDEX			0x1CF0
+#define DC_DISPLAY_GAMMA_EX_DATA			0x1CF8
+#define DC_DISPLAY_GAMMA_EX_ONE_DATA		0x1D80
+#define DC_DISPLAY_RGBTOYUV_COEF0			0x1E48
+#define DC_DISPLAY_RGBTOYUV_COEF1			0x1E50
+#define DC_DISPLAY_RGBTOYUV_COEF2			0x1E58
+#define DC_DISPLAY_RGBTOYUV_COEF3			0x1E60
+#define DC_DISPLAY_RGBTOYUV_COEF4			0x1E68
+#define DC_DISPLAY_RGBTOYUV_COEFD0			0x1E70
+#define DC_DISPLAY_RGBTOYUV_COEFD1			0x1E78
+#define DC_DISPLAY_RGBTOYUV_COEFD2			0x1E80
+
+#define DC_CLK_GATTING					0x1A28
+#define DC_QOS_CONFIG					0x1A38
+
+#define DC_TRANSPARENCY_OPAQUE			0x00
+#define DC_TRANSPARENCY_KEY				0x02
+#define DC_DISPLAY_DITHERTABLE_LOW		0x7B48F3C0
+#define DC_DISPLAY_DITHERTABLE_HIGH		0x596AD1E2
+
+#define GAMMA_SIZE						256
+#define GAMMA_EX_SIZE					300
+#define DEGAMMA_SIZE					260
+
+#define RGB_TO_RGB_TABLE_SIZE			9
+#define YUV_TO_RGB_TABLE_SIZE			16
+#define RGB_TO_YUV_TABLE_SIZE			12
+
+#define DC_LAYER_NUM	6
+#define DC_DISPLAY_NUM	2
+#define DC_CURSOR_NUM	2
+
+#define DC_TILE_MODE4X4	0x15
+
+enum dc_chip_rev {
+	DC_REV_0,/* For HW_REV_5720,HW_REV_5721_311 */
+	DC_REV_1,/* For HW_REV_5721_30B */
+	DC_REV_2,/* For HW_REV_5721_310 */
+};
+
+enum dc_hw_plane_id {
+	PRIMARY_PLANE_0,
+	OVERLAY_PLANE_0,
+	OVERLAY_PLANE_1,
+	PRIMARY_PLANE_1,
+	OVERLAY_PLANE_2,
+	OVERLAY_PLANE_3,
+	CURSOR_PLANE_0,
+	CURSOR_PLANE_1,
+	PLANE_NUM
+};
+
+enum dc_hw_color_format {
+	FORMAT_X4R4G4B4,//0
+	FORMAT_A4R4G4B4,//1
+	FORMAT_X1R5G5B5,//2
+	FORMAT_A1R5G5B5,//3
+	FORMAT_R5G6B5,//4
+	FORMAT_X8R8G8B8,//5
+	FORMAT_A8R8G8B8,//6
+	FORMAT_YUY2,//7
+	FORMAT_UYVY,//8
+	FORMAT_INDEX8,//9
+	FORMAT_MONOCHROME,//10
+	FORMAT_YV12 = 0xf,
+	FORMAT_A8,//16
+	FORMAT_NV12,//17
+	FORMAT_NV16,//18
+	FORMAT_RG16,//19
+	FORMAT_R8,//20
+	FORMAT_NV12_10BIT,//21
+	FORMAT_A2R10G10B10,//22
+	FORMAT_NV16_10BIT,//23
+	FORMAT_INDEX1,//24
+	FORMAT_INDEX2,//25
+	FORMAT_INDEX4,//26
+	FORMAT_P010,//27
+	FORMAT_YUV444,//28
+	FORMAT_YUV444_10BIT,//29
+};
+
+enum dc_hw_yuv_color_space {
+	COLOR_SPACE_601 = 0,
+	COLOR_SPACE_709 = 1,
+	COLOR_SPACE_2020 = 3,
+};
+
+enum dc_hw_rotation {
+	ROT_0 = 0,
+	ROT_90 = 4,
+	ROT_180 = 5,
+	ROT_270 = 6,
+	FLIP_X = 1,
+	FLIP_Y = 2,
+	FLIP_XY = 3,
+};
+
+enum dc_hw_swizzle {
+	SWIZZLE_ARGB = 0,
+	SWIZZLE_RGBA,
+	SWIZZLE_ABGR,
+	SWIZZLE_BGRA,
+};
+
+enum dc_hw_out {
+	OUT_DPI,
+	OUT_DP,
+};
+
+enum dc_hw_cursor_size {
+	CURSOR_SIZE_32X32 = 0,
+	CURSOR_SIZE_64X64,
+};
+
+enum dc_hw_blend_mode {
+	/* out.rgb = plane_alpha * fg.rgb +
+	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
+	 */
+	BLEND_PREMULTI,
+	/* out.rgb = plane_alpha * fg.alpha * fg.rgb +
+	 *		(1 - (plane_alpha * fg.alpha)) * bg.rgb
+	 */
+	BLEND_COVERAGE,
+	/* out.rgb = plane_alpha * fg.rgb +
+	 *		(1 - plane_alpha) * bg.rgb
+	 */
+	BLEND_PIXEL_NONE,
+};
+
+struct dc_hw_plane_reg {
+	u32 y_address;
+	u32 u_address;
+	u32 v_address;
+	u32 y_stride;
+	u32 u_stride;
+	u32 v_stride;
+	u32 size;
+	u32 top_left;
+	u32 bottom_right;
+	u32 scale_factor_x;
+	u32 scale_factor_y;
+	u32 h_filter_coef_index;
+	u32 h_filter_coef_data;
+	u32 v_filter_coef_index;
+	u32 v_filter_coef_data;
+	u32 init_offset;
+	u32 color_key;
+	u32 color_key_high;
+	u32 clear_value;
+	u32 color_table_index;
+	u32 color_table_data;
+	u32 scale_config;
+	u32 water_mark;
+	u32 degamma_index;
+	u32 degamma_data;
+	u32 degamma_ex_data;
+	u32 src_global_color;
+	u32 dst_global_color;
+	u32 blend_config;
+	u32 roi_origin;
+	u32 roi_size;
+	u32 yuv_to_rgb_coef0;
+	u32 yuv_to_rgb_coef1;
+	u32 yuv_to_rgb_coef2;
+	u32 yuv_to_rgb_coef3;
+	u32 yuv_to_rgb_coef4;
+	u32 yuv_to_rgb_coefd0;
+	u32 yuv_to_rgb_coefd1;
+	u32 yuv_to_rgb_coefd2;
+	u32 y_clamp_bound;
+	u32 uv_clamp_bound;
+	u32 rgb_to_rgb_coef0;
+	u32 rgb_to_rgb_coef1;
+	u32 rgb_to_rgb_coef2;
+	u32 rgb_to_rgb_coef3;
+	u32 rgb_to_rgb_coef4;
+};
+
+struct dc_hw_fb {
+	u32 y_address;
+	u32 u_address;
+	u32 v_address;
+	u32 clear_value;
+	u32 water_mark;
+	u16 y_stride;
+	u16 u_stride;
+	u16 v_stride;
+	u16 width;
+	u16 height;
+	u8	format;
+	u8	tile_mode;
+	u8	rotation;
+	u8	yuv_color_space;
+	u8	swizzle;
+	u8	uv_swizzle;
+	u8	zpos;
+	u8	display_id;
+	bool	clear_enable;
+	bool	dec_enable;
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_scale {
+	u32 scale_factor_x;
+	u32 scale_factor_y;
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_position {
+	u16 start_x;
+	u16 start_y;
+	u16 end_x;
+	u16 end_y;
+	bool	dirty;
+};
+
+struct dc_hw_blend {
+	u8	alpha;
+	u8	blend_mode;
+	bool	dirty;
+};
+
+struct dc_hw_colorkey {
+	u32 colorkey;
+	u32 colorkey_high;
+	u8	transparency;
+	bool dirty;
+};
+
+struct dc_hw_roi {
+	u16 x;
+	u16 y;
+	u16 width;
+	u16 height;
+	bool enable;
+	bool dirty;
+};
+
+struct dc_hw_cursor {
+	u32 address;
+	u16 x;
+	u16 y;
+	u16 hot_x;
+	u16 hot_y;
+	u8	size;
+	u8	display_id;
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_display {
+	u32 bus_format;
+	u16 h_active;
+	u16 h_total;
+	u16 h_sync_start;
+	u16 h_sync_end;
+	u16 v_active;
+	u16 v_total;
+	u16 v_sync_start;
+	u16 v_sync_end;
+	u8	id;
+	bool	h_sync_polarity;
+	bool	v_sync_polarity;
+	bool	enable;
+};
+
+struct dc_hw_gamma {
+	u16 gamma[GAMMA_EX_SIZE][3];
+	bool	enable;
+	bool	dirty;
+};
+
+struct dc_hw_degamma {
+	u16 degamma[DEGAMMA_SIZE][3];
+	u32 mode;
+	bool	dirty;
+};
+
+struct dc_hw_plane {
+	struct dc_hw_fb			fb;
+	struct dc_hw_position	pos;
+	struct dc_hw_scale		scale;
+	struct dc_hw_blend		blend;
+	struct dc_hw_roi		roi;
+	struct dc_hw_colorkey	colorkey;
+	struct dc_hw_degamma	degamma;
+};
+
+struct dc_hw_qos {
+	u8	  low_value;
+	u8	  high_value;
+	bool  dirty;
+};
+
+struct dc_hw_read {
+	u32			reg;
+	u32			value;
+};
+
+struct dc_hw;
+struct dc_hw_funcs {
+	void (*gamma)(struct dc_hw *hw);
+	void (*plane)(struct dc_hw *hw);
+	void (*display)(struct dc_hw *hw, struct dc_hw_display *display);
+};
+
+struct dc_hw {
+	enum dc_chip_rev rev;
+	enum dc_hw_out		out[DC_DISPLAY_NUM];
+	void			*hi_base;
+	void			*reg_base;
+
+	struct dc_hw_display display[DC_DISPLAY_NUM];
+	struct dc_hw_gamma	 gamma[DC_DISPLAY_NUM];
+	struct dc_hw_plane	 plane[DC_LAYER_NUM];
+	struct dc_hw_cursor  cursor[DC_CURSOR_NUM];
+	struct dc_hw_qos	 qos;
+	struct dc_hw_funcs	 *func;
+	struct vs_dc_info	 *info;
+};
+
+int dc_hw_init(struct dc_hw *hw);
+void dc_hw_deinit(struct dc_hw *hw);
+void dc_hw_update_plane(struct dc_hw *hw, u8 id,
+			struct dc_hw_fb *fb, struct dc_hw_scale *scale,
+			struct dc_hw_position *pos, struct dc_hw_blend *blend);
+void dc_hw_update_degamma(struct dc_hw *hw, u8 id, u32 mode);
+void dc_hw_update_roi(struct dc_hw *hw, u8 id, struct dc_hw_roi *roi);
+void dc_hw_update_colorkey(struct dc_hw *hw, u8 id,
+			   struct dc_hw_colorkey *colorkey);
+void dc_hw_update_qos(struct dc_hw *hw, struct dc_hw_qos *qos);
+void dc_hw_update_cursor(struct dc_hw *hw, u8 id, struct dc_hw_cursor *cursor);
+void dc_hw_update_gamma(struct dc_hw *hw, u8 id, u16 index,
+			u16 r, u16 g, u16 b);
+void dc_hw_enable_gamma(struct dc_hw *hw, u8 id, bool enable);
+void dc_hw_setup_display(struct dc_hw *hw, struct dc_hw_display *display);
+void dc_hw_enable_interrupt(struct dc_hw *hw, bool enable);
+u32 dc_hw_get_interrupt(struct dc_hw *hw);
+bool dc_hw_check_underflow(struct dc_hw *hw);
+void dc_hw_enable_shadow_register(struct dc_hw *hw, bool enable);
+void dc_hw_set_out(struct dc_hw *hw, enum dc_hw_out out, u8 id);
+void dc_hw_commit(struct dc_hw *hw);
+
+#endif /* __VS_DC_HW_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c
index da7698c3d..3cd533cfa 100644
--- a/drivers/gpu/drm/verisilicon/vs_drv.c
+++ b/drivers/gpu/drm/verisilicon/vs_drv.c
@@ -21,6 +21,7 @@ 
 
 #include "vs_drv.h"
 #include "vs_modeset.h"
+#include "vs_dc.h"
 
 #define DRV_NAME	"verisilicon"
 #define DRV_DESC	"Verisilicon DRM driver"
@@ -123,6 +124,7 @@  static const struct component_master_ops vs_drm_ops = {
 };
 
 static struct platform_driver *drm_sub_drivers[] = {
+	&dc_platform_driver,
 
 };
 
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
new file mode 100644
index 000000000..9bd066015
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.c
@@ -0,0 +1,526 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_fb_dma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+
+#include <drm/vs_drm.h>
+
+#include "vs_plane.h"
+#include "vs_drv.h"
+#include "vs_dc.h"
+
+static void vs_plane_reset(struct drm_plane *plane)
+{
+	struct vs_plane_state *state;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+
+	if (plane->state) {
+		__drm_atomic_helper_plane_destroy_state(plane->state);
+
+		state = to_vs_plane_state(plane->state);
+		kfree(state);
+		plane->state = NULL;
+	}
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	state->degamma = VS_DEGAMMA_DISABLE;
+	state->degamma_changed = false;
+	state->base.zpos = vs_plane->id;
+	memset(&state->status, 0, sizeof(state->status));
+
+	__drm_atomic_helper_plane_reset(plane, &state->base);
+}
+
+static void _vs_plane_duplicate_blob(struct vs_plane_state *state,
+				     struct vs_plane_state *ori_state)
+{
+	state->watermark = ori_state->watermark;
+	state->color_mgmt = ori_state->color_mgmt;
+	state->roi = ori_state->roi;
+
+	if (state->watermark)
+		drm_property_blob_get(state->watermark);
+	if (state->color_mgmt)
+		drm_property_blob_get(state->color_mgmt);
+	if (state->roi)
+		drm_property_blob_get(state->roi);
+}
+
+static int
+_vs_plane_set_property_blob_from_id(struct drm_device *dev,
+				    struct drm_property_blob **blob,
+				    u64 blob_id,
+				    size_t expected_size)
+{
+	struct drm_property_blob *new_blob = NULL;
+
+	if (blob_id) {
+		new_blob = drm_property_lookup_blob(dev, blob_id);
+		if (!new_blob)
+			return -EINVAL;
+
+		if (new_blob->length != expected_size) {
+			drm_property_blob_put(new_blob);
+			return -EINVAL;
+		}
+	}
+
+	drm_property_replace_blob(blob, new_blob);
+	drm_property_blob_put(new_blob);
+
+	return 0;
+}
+
+static struct drm_plane_state *
+vs_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+	struct vs_plane_state *ori_state;
+	struct vs_plane_state *state;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	ori_state = to_vs_plane_state(plane->state);
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
+
+	state->degamma = ori_state->degamma;
+	state->degamma_changed = ori_state->degamma_changed;
+
+	_vs_plane_duplicate_blob(state, ori_state);
+	memcpy(&state->status, &ori_state->status, sizeof(ori_state->status));
+
+	return &state->base;
+}
+
+static void vs_plane_atomic_destroy_state(struct drm_plane *plane,
+					  struct drm_plane_state *state)
+{
+	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
+
+	__drm_atomic_helper_plane_destroy_state(state);
+
+	drm_property_blob_put(vs_plane_state->watermark);
+	drm_property_blob_put(vs_plane_state->color_mgmt);
+	drm_property_blob_put(vs_plane_state->roi);
+	kfree(vs_plane_state);
+}
+
+static int vs_plane_atomic_set_property(struct drm_plane *plane,
+					struct drm_plane_state *state,
+					struct drm_property *property,
+					uint64_t val)
+{
+	struct drm_device *dev = plane->dev;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_plane_state *vs_plane_state = to_vs_plane_state(state);
+	int ret = 0;
+
+	if (property == vs_plane->degamma_mode) {
+		if (vs_plane_state->degamma != val) {
+			vs_plane_state->degamma = val;
+			vs_plane_state->degamma_changed = true;
+		} else {
+			vs_plane_state->degamma_changed = false;
+		}
+	} else if (property == vs_plane->watermark_prop) {
+		ret = _vs_plane_set_property_blob_from_id(dev,
+							  &vs_plane_state->watermark,
+							  val,
+							  sizeof(struct drm_vs_watermark));
+		return ret;
+	} else if (property == vs_plane->color_mgmt_prop) {
+		ret = _vs_plane_set_property_blob_from_id(dev,
+							  &vs_plane_state->color_mgmt,
+							  val,
+							  sizeof(struct drm_vs_color_mgmt));
+		return ret;
+	} else if (property == vs_plane->roi_prop) {
+		ret = _vs_plane_set_property_blob_from_id(dev,
+							  &vs_plane_state->roi,
+							  val,
+							  sizeof(struct drm_vs_roi));
+		return ret;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vs_plane_atomic_get_property(struct drm_plane *plane,
+					const struct drm_plane_state *state,
+					struct drm_property *property,
+					uint64_t *val)
+{
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	const struct vs_plane_state *vs_plane_state =
+		container_of(state, const struct vs_plane_state, base);
+
+	if (property == vs_plane->degamma_mode)
+		*val = vs_plane_state->degamma;
+	else if (property == vs_plane->watermark_prop)
+		*val = (vs_plane_state->watermark) ?
+					vs_plane_state->watermark->base.id : 0;
+	else if (property == vs_plane->color_mgmt_prop)
+		*val = (vs_plane_state->color_mgmt) ?
+					vs_plane_state->color_mgmt->base.id : 0;
+	else if (property == vs_plane->roi_prop)
+		*val = (vs_plane_state->roi) ?
+					vs_plane_state->roi->base.id : 0;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static bool vs_format_mod_supported(struct drm_plane *plane,
+				    u32 format,
+				    u64 modifier)
+{
+	int i;
+
+	/* We always have to allow these modifiers:
+	 * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
+	 * 2. Not passing any modifiers is the same as explicitly passing INVALID.
+	 */
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	/* Check that the modifier is on the list of the plane's supported modifiers. */
+	for (i = 0; i < plane->modifier_count; i++) {
+		if (modifier == plane->modifiers[i])
+			break;
+	}
+
+	if (i == plane->modifier_count)
+		return false;
+
+	return true;
+}
+
+const struct drm_plane_funcs vs_plane_funcs = {
+	.update_plane		= drm_atomic_helper_update_plane,
+	.disable_plane		= drm_atomic_helper_disable_plane,
+	.reset			= vs_plane_reset,
+	.atomic_duplicate_state = vs_plane_atomic_duplicate_state,
+	.atomic_destroy_state	= vs_plane_atomic_destroy_state,
+	.atomic_set_property	= vs_plane_atomic_set_property,
+	.atomic_get_property	= vs_plane_atomic_get_property,
+	.format_mod_supported	= vs_format_mod_supported,
+};
+
+static unsigned char vs_get_plane_number(struct drm_framebuffer *fb)
+{
+	const struct drm_format_info *info;
+
+	if (!fb)
+		return 0;
+
+	info = drm_format_info(fb->format->format);
+	if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES)
+		return 0;
+
+	return info->num_planes;
+}
+
+static int vs_plane_atomic_check(struct drm_plane *plane,
+				 struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+										 plane);
+	unsigned char i, num_planes;
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	struct drm_crtc *crtc = new_plane_state->crtc;
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+	struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
+
+	if (!crtc || !fb)
+		return 0;
+
+	num_planes = vs_get_plane_number(fb);
+
+	for (i = 0; i < num_planes; i++) {
+		dma_addr_t dma_addr;
+
+		dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
+		plane_state->dma_addr[i] = dma_addr;
+	}
+
+	return vs_dc_check_plane(dc, plane, state);
+}
+
+static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
+					struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+									  plane);
+	unsigned char i, num_planes;
+	struct drm_framebuffer *fb = new_plane_state->fb;
+	struct drm_crtc *crtc = new_plane_state->crtc;
+	struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+	struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state);
+
+	if (!crtc || !fb)
+		return 0;
+
+	num_planes = vs_get_plane_number(fb);
+
+	for (i = 0; i < num_planes; i++) {
+		dma_addr_t dma_addr;
+
+		dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i);
+		plane_state->dma_addr[i] = dma_addr;
+	}
+
+	return vs_dc_check_cursor_plane(dc, plane, state);
+}
+
+static void vs_plane_atomic_update(struct drm_plane *plane,
+				   struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+									  plane);
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+									  plane);
+
+	unsigned char i, num_planes;
+	struct drm_framebuffer *fb;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
+	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	if (!new_state->fb || !new_state->crtc)
+		return;
+
+	fb = new_state->fb;
+
+	drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
+
+	num_planes = vs_get_plane_number(fb);
+
+	for (i = 0; i < num_planes; i++) {
+		dma_addr_t dma_addr;
+
+		dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
+		plane_state->dma_addr[i] = dma_addr;
+	}
+
+	plane_state->status.src = drm_plane_state_src(new_state);
+	plane_state->status.dest = drm_plane_state_dest(new_state);
+
+	vs_dc_update_plane(dc, vs_plane, plane, state);
+}
+
+static void vs_cursor_plane_atomic_update(struct drm_plane *plane,
+					  struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+									   plane);
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+									   plane);
+	unsigned char i, num_planes;
+	struct drm_framebuffer *fb;
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc);
+	struct vs_plane_state *plane_state = to_vs_plane_state(new_state);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	if (!new_state->fb || !new_state->crtc)
+		return;
+
+	fb = new_state->fb;
+	drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state);
+
+	num_planes = vs_get_plane_number(fb);
+
+	for (i = 0; i < num_planes; i++) {
+		dma_addr_t dma_addr;
+
+		dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i);
+		plane_state->dma_addr[i] = dma_addr;
+	}
+
+	plane_state->status.src = drm_plane_state_src(new_state);
+	plane_state->status.dest = drm_plane_state_dest(new_state);
+
+	vs_dc_update_cursor_plane(dc, vs_plane, plane, state);
+}
+
+static void vs_plane_atomic_disable(struct drm_plane *plane,
+				    struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+									   plane);
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	vs_dc_disable_plane(dc, vs_plane, old_state);
+}
+
+static void vs_cursor_plane_atomic_disable(struct drm_plane *plane,
+					   struct drm_atomic_state *state)
+{
+	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+									   plane);
+	struct vs_plane *vs_plane = to_vs_plane(plane);
+	struct vs_crtc *vs_crtc = to_vs_crtc(old_state->crtc);
+	struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev);
+
+	vs_dc_disable_cursor_plane(dc, vs_plane, old_state);
+}
+
+const struct drm_plane_helper_funcs primary_plane_helpers = {
+	.atomic_check	= vs_plane_atomic_check,
+	.atomic_update	= vs_plane_atomic_update,
+	.atomic_disable = vs_plane_atomic_disable,
+};
+
+const struct drm_plane_helper_funcs overlay_plane_helpers = {
+	.atomic_check	= vs_plane_atomic_check,
+	.atomic_update	= vs_plane_atomic_update,
+	.atomic_disable = vs_plane_atomic_disable,
+};
+
+const struct drm_plane_helper_funcs cursor_plane_helpers = {
+	.atomic_check	= vs_cursor_plane_atomic_check,
+	.atomic_update	= vs_cursor_plane_atomic_update,
+	.atomic_disable = vs_cursor_plane_atomic_disable,
+};
+
+static const struct drm_prop_enum_list vs_degamma_mode_enum_list[] = {
+	{ VS_DEGAMMA_DISABLE,	"disabled" },
+	{ VS_DEGAMMA_BT709,	"preset degamma for BT709" },
+	{ VS_DEGAMMA_BT2020,	"preset degamma for BT2020" },
+};
+
+struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
+				 struct vs_plane_info *info,
+				 unsigned int layer_num,
+				 unsigned int possible_crtcs)
+{
+	struct vs_plane *plane;
+	int ret;
+
+	if (!info)
+		return NULL;
+
+	plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
+					   possible_crtcs,
+					   &vs_plane_funcs,
+					   info->formats, info->num_formats,
+					   info->modifiers, info->type,
+					   info->name ? info->name : NULL);
+	if (IS_ERR(plane))
+		return ERR_CAST(plane);
+
+	if (info->type == DRM_PLANE_TYPE_PRIMARY)
+		drm_plane_helper_add(&plane->base, &primary_plane_helpers);
+	else if (info->type == DRM_PLANE_TYPE_CURSOR)
+		drm_plane_helper_add(&plane->base, &cursor_plane_helpers);
+	else
+		drm_plane_helper_add(&plane->base, &overlay_plane_helpers);
+
+	/* Set up the plane properties */
+	if (info->degamma_size) {
+		plane->degamma_mode =
+		drm_property_create_enum(drm_dev, 0,
+					 "DEGAMMA_MODE",
+					 vs_degamma_mode_enum_list,
+					 ARRAY_SIZE(vs_degamma_mode_enum_list));
+
+		if (!plane->degamma_mode)
+			return NULL;
+
+		drm_object_attach_property(&plane->base.base,
+					   plane->degamma_mode,
+					   VS_DEGAMMA_DISABLE);
+	}
+
+	if (info->rotation) {
+		ret = drm_plane_create_rotation_property(&plane->base,
+							 DRM_MODE_ROTATE_0,
+							 info->rotation);
+		if (ret)
+			return NULL;
+	}
+
+	if (info->blend_mode) {
+		ret = drm_plane_create_blend_mode_property(&plane->base,
+							   info->blend_mode);
+		if (ret)
+			return NULL;
+		ret = drm_plane_create_alpha_property(&plane->base);
+		if (ret)
+			return NULL;
+	}
+
+	if (info->color_encoding) {
+		ret = drm_plane_create_color_properties(&plane->base,
+							info->color_encoding,
+							BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+							DRM_COLOR_YCBCR_BT709,
+							DRM_COLOR_YCBCR_LIMITED_RANGE);
+		if (ret)
+			return NULL;
+	}
+
+	if (info->zpos != 255) {
+		ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0,
+						     layer_num - 1);
+		if (ret)
+			return NULL;
+	} else {
+		ret = drm_plane_create_zpos_immutable_property(&plane->base,
+							       info->zpos);
+		if (ret)
+			return NULL;
+	}
+
+	if (info->watermark) {
+		plane->watermark_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
+							    "WATERMARK", 0);
+		if (!plane->watermark_prop)
+			return NULL;
+		drm_object_attach_property(&plane->base.base, plane->watermark_prop, 0);
+	}
+
+	if (info->color_mgmt) {
+		plane->color_mgmt_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
+							     "COLOR_CONFIG", 0);
+		if (!plane->color_mgmt_prop)
+			return NULL;
+
+		drm_object_attach_property(&plane->base.base, plane->color_mgmt_prop, 0);
+	}
+
+	if (info->roi) {
+		plane->roi_prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB,
+						      "ROI", 0);
+		if (!plane->roi_prop)
+			return NULL;
+
+		drm_object_attach_property(&plane->base.base, plane->roi_prop, 0);
+	}
+
+	return plane;
+}
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h
new file mode 100644
index 000000000..554b74e96
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.h
@@ -0,0 +1,58 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_PLANE_H__
+#define __VS_PLANE_H__
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane_helper.h>
+
+#include "vs_type.h"
+
+struct vs_plane_status {
+	u32 tile_mode;
+	struct drm_rect src;
+	struct drm_rect dest;
+};
+
+struct vs_plane_state {
+	struct drm_plane_state base;
+	struct vs_plane_status status; /* for debugfs */
+
+	struct drm_property_blob *watermark;
+	struct drm_property_blob *color_mgmt;
+	struct drm_property_blob *roi;
+	dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES];
+
+	u32 degamma;
+	bool degamma_changed;
+};
+
+struct vs_plane {
+	struct drm_plane base;
+	u8 id;
+
+	struct drm_property *degamma_mode;
+	struct drm_property *watermark_prop;
+	struct drm_property *color_mgmt_prop;
+	struct drm_property *roi_prop;
+};
+
+struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
+				 struct vs_plane_info *info,
+				 unsigned int layer_num,
+				 unsigned int possible_crtcs);
+
+static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
+{
+	return container_of(plane, struct vs_plane, base);
+}
+
+static inline struct vs_plane_state *
+to_vs_plane_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct vs_plane_state, base);
+}
+#endif /* __VS_PLANE_H__ */
diff --git a/drivers/gpu/drm/verisilicon/vs_type.h b/drivers/gpu/drm/verisilicon/vs_type.h
new file mode 100644
index 000000000..7d3378e29
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_type.h
@@ -0,0 +1,69 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_TYPE_H__
+#define __VS_TYPE_H__
+
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+
+struct vs_plane_info {
+	const char *name;
+	u8 id;
+	enum drm_plane_type type;
+	unsigned int num_formats;
+	const u32 *formats;
+	u8 num_modifiers;
+	const u64 *modifiers;
+	unsigned int min_width;
+	unsigned int min_height;
+	unsigned int max_width;
+	unsigned int max_height;
+	unsigned int rotation;
+	unsigned int blend_mode;
+	unsigned int color_encoding;
+
+	/* 0 means no de-gamma LUT */
+	unsigned int degamma_size;
+
+	int min_scale; /* 16.16 fixed point */
+	int max_scale; /* 16.16 fixed point */
+
+	/* default zorder value,
+	 * and 255 means unsupported zorder capability
+	 */
+	u8	 zpos;
+
+	bool watermark;
+	bool color_mgmt;
+	bool roi;
+};
+
+struct vs_dc_info {
+	const char *name;
+
+	u8 panel_num;
+
+	/* planes */
+	u8 plane_num;
+	const struct vs_plane_info *planes;
+
+	u8 layer_num;
+	unsigned int max_bpc;
+	unsigned int color_formats;
+
+	/* 0 means no gamma LUT */
+	u16 gamma_size;
+	u8 gamma_bits;
+
+	u16 pitch_alignment;
+
+	bool pipe_sync;
+	bool background;
+	bool panel_sync;
+	bool cap_dec;
+};
+
+#endif /* __VS_TYPE_H__ */