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

Thomas Zimmermann tzimmermann at suse.de
Fri Nov 24 05:40:18 PST 2023


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


-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20231124/9f7ac78f/attachment.sig>


More information about the linux-riscv mailing list