lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251223-mtk-ovl-pre-blend-colorops-v1-5-0cb99bd0ab33@collabora.com>
Date: Tue, 23 Dec 2025 16:44:46 -0300
From: Nícolas F. R. A. Prado <nfraprado@...labora.com>
To: Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>, 
 Maxime Ripard <mripard@...nel.org>, Thomas Zimmermann <tzimmermann@...e.de>, 
 David Airlie <airlied@...il.com>, Simona Vetter <simona@...ll.ch>, 
 Chun-Kuang Hu <chunkuang.hu@...nel.org>, 
 Philipp Zabel <p.zabel@...gutronix.de>, 
 Matthias Brugger <matthias.bgg@...il.com>, 
 AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com>
Cc: dri-devel@...ts.freedesktop.org, linux-kernel@...r.kernel.org, 
 linux-mediatek@...ts.infradead.org, linux-arm-kernel@...ts.infradead.org, 
 daniels@...labora.com, ariel.dalessandro@...labora.com, 
 kernel@...labora.com, 
 Nícolas F. R. A. Prado <nfraprado@...labora.com>
Subject: [PATCH 05/11] drm/mediatek: ovl: Implement support for Inverse
 Gamma

The OVL hardware allows selecting between different fixed transfer
functions for each layer through the Inverse Gamma setting. Available
functions are scRGB and BT.709. Implement support for it and expose it
as a colorop through the DRM plane color pipeline uAPI.

Signed-off-by: Nícolas F. R. A. Prado <nfraprado@...labora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |   1 +
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 169 ++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index e0c30c6c7cc8..fde31e3fcc4a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -115,6 +115,7 @@ void mtk_ovl_disable_vblank(struct device *dev);
 u32 mtk_ovl_get_blend_modes(struct device *dev);
 const u32 *mtk_ovl_get_formats(struct device *dev);
 size_t mtk_ovl_get_num_formats(struct device *dev);
+int mtk_ovl_plane_colorops_init(struct device *dev, struct drm_plane *plane);
 bool mtk_ovl_is_afbc_supported(struct device *dev);
 
 void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index cfc6a3154f73..4eaa31541ccc 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -4,8 +4,11 @@
  */
 
 #include <drm/drm_blend.h>
+#include <drm/drm_colorop.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
 
 #include <linux/clk.h>
 #include <linux/component.h>
@@ -47,6 +50,12 @@
 #define OVL_CON_CLRFMT_BIT_DEPTH(depth, n)		((depth) << (4 * (n)))
 #define OVL_CON_CLRFMT_8_BIT				(0)
 #define OVL_CON_CLRFMT_10_BIT				(1)
+#define DISP_REG_OVL_WCG_CFG1			0x2d8
+#define IGAMMA_EN(layer)				BIT(0 + 4 * (layer))
+#define DISP_REG_OVL_WCG_CFG2			0x2dc
+#define IGAMMA_MASK(layer)				GENMASK((layer) * 4 + 1, (layer) * 4)
+#define IGAMMA_SCRGB					0
+#define IGAMMA_BT709					1
 #define DISP_REG_OVL_ADDR_MT8173		0x0f40
 #define DISP_REG_OVL_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n))
 #define DISP_REG_OVL_HDR_ADDR(ovl, n)		((ovl)->data->addr + 0x20 * (n) + 0x04)
@@ -492,6 +501,91 @@ static void mtk_ovl_afbc_layer_config(struct mtk_disp_ovl *ovl,
 	}
 }
 
+static int mtk_ovl_colorop_curve_to_reg_val(enum drm_colorop_curve_1d_type curve)
+{
+	switch (curve) {
+	case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
+		return IGAMMA_SCRGB;
+	case DRM_COLOROP_1D_CURVE_BT2020_OETF:
+		return IGAMMA_BT709;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void mtk_ovl_apply_igamma(struct mtk_disp_ovl *ovl, unsigned int idx,
+				 struct drm_colorop *colorop,
+				 struct cmdq_pkt *cmdq_pkt)
+{
+	int curve_reg_val;
+
+	if (colorop->state->bypass) {
+		/* igamma curve needs to be set to default when igamma is disabled */
+		curve_reg_val = IGAMMA_SCRGB;
+	} else {
+		curve_reg_val = mtk_ovl_colorop_curve_to_reg_val(colorop->state->curve_1d_type);
+		if (curve_reg_val < 0) {
+			drm_WARN(ovl->crtc->dev, 1,
+				 "Invalid curve 1d type %u\n",
+				 colorop->state->curve_1d_type);
+			return;
+		}
+	}
+
+	mtk_ddp_write_mask(cmdq_pkt,
+			   field_prep(IGAMMA_MASK(idx), curve_reg_val),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG2,
+			   IGAMMA_MASK(idx));
+
+	mtk_ddp_write_mask(cmdq_pkt,
+			   colorop->state->bypass ? 0 : IGAMMA_EN(idx),
+			   &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_WCG_CFG1,
+			   IGAMMA_EN(idx));
+}
+
+static void mtk_ovl_apply_colorop(struct mtk_disp_ovl *ovl, unsigned int idx,
+				  struct drm_colorop *colorop,
+				  struct cmdq_pkt *cmdq_pkt)
+{
+	switch (colorop->type) {
+	case DRM_COLOROP_1D_CURVE:
+		mtk_ovl_apply_igamma(ovl, idx, colorop, cmdq_pkt);
+		break;
+	default:
+		drm_WARN(ovl->crtc->dev, 1, "Invalid colorop type %u\n", colorop->type);
+		break;
+	}
+}
+
+static void mtk_ovl_disable_colorops(struct mtk_disp_ovl *ovl, unsigned int idx,
+				     struct cmdq_pkt *cmdq_pkt)
+{
+	mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
+			   DISP_REG_OVL_WCG_CFG1,
+			   IGAMMA_EN(idx));
+
+	/* igamma curve needs to be set to default when igamma is disabled */
+	mtk_ddp_write_mask(cmdq_pkt, IGAMMA_SCRGB, &ovl->cmdq_reg, ovl->regs,
+			   DISP_REG_OVL_WCG_CFG2, IGAMMA_MASK(idx));
+}
+
+static void mtk_ovl_apply_colorops(struct mtk_disp_ovl *ovl, unsigned int idx,
+				   struct mtk_plane_state *state,
+				   struct cmdq_pkt *cmdq_pkt)
+{
+	if (!ovl->data->supports_plane_colorops)
+		return;
+
+	if (!state->base.color_pipeline) {
+		mtk_ovl_disable_colorops(ovl, idx, cmdq_pkt);
+		return;
+	}
+
+	for (struct drm_colorop *colorop = state->base.color_pipeline; colorop;
+	     colorop = colorop->next)
+		mtk_ovl_apply_colorop(ovl, idx, colorop, cmdq_pkt);
+}
+
 void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 			  struct mtk_plane_state *state,
 			  struct cmdq_pkt *cmdq_pkt)
@@ -513,6 +607,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 		return;
 	}
 
+	mtk_ovl_apply_colorops(ovl, idx, state, cmdq_pkt);
+
 	con = mtk_ovl_fmt_convert(ovl, state);
 	if (state->base.fb) {
 		con |= state->base.alpha & OVL_CON_ALPHA;
@@ -593,6 +689,79 @@ void mtk_ovl_bgclr_in_off(struct device *dev)
 	writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 }
 
+static const struct drm_colorop_funcs mtk_ovl_colorop_funcs = {
+	.destroy = drm_colorop_destroy,
+};
+
+static const u64 igamma_supported_tfs =
+	BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
+	BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF);
+
+#define MAX_COLOR_PIPELINE_OPS 3
+
+static int
+mtk_ovl_initialize_plane_color_pipeline(struct drm_plane *plane,
+					struct drm_prop_enum_list *pipeline)
+{
+	struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
+	struct drm_device *dev = plane->dev;
+	int i = 0;
+	int ret;
+
+	memset(ops, 0, sizeof(ops));
+
+	/* 1st op: OVL's Inverse Gamma */
+	ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+	if (!ops[i]) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane,
+					      &mtk_ovl_colorop_funcs,
+					      igamma_supported_tfs,
+					      DRM_COLOROP_FLAG_ALLOW_BYPASS);
+	if (ret)
+		goto err_colorop_init;
+
+	pipeline->type = ops[0]->base.id;
+	pipeline->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id);
+
+	return 0;
+
+err_colorop_init:
+	kfree(ops[i]);
+
+err_alloc:
+	i--;
+	for (; i >= 0; i--) {
+		drm_colorop_cleanup(ops[i]);
+		kfree(ops[i]);
+	}
+
+	return ret;
+}
+
+int mtk_ovl_plane_colorops_init(struct device *dev, struct drm_plane *plane)
+{
+	struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+	struct drm_prop_enum_list pipeline = {};
+	int ret;
+
+	if (!ovl->data->supports_plane_colorops)
+		return 0;
+
+	ret = mtk_ovl_initialize_plane_color_pipeline(plane, &pipeline);
+	if (ret)
+		return ret;
+
+	ret = drm_plane_create_color_pipeline_property(plane, &pipeline, 1);
+
+	kfree(pipeline.name);
+
+	return ret;
+}
+
 static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
 			     void *data)
 {

-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ