From nobody Fri Oct 3 23:02:08 2025 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A64B82BFC85 for ; Fri, 22 Aug 2025 18:36:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887807; cv=none; b=n5vjc+JF/12hZDwJauzJRnZhGvUXJFSjQQ5ypEEshc0FQyxE1D0bJhy7/PimCW5h5LK9r714BSS+5uBPeh78cY4CG9OZMERZLWNZ4p+TuB0gogfb4nWn0wPxCUueldX0eq0amgTLscezYwwvqm8az8FUCB7oqn3eulwB6VR9hTw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887807; c=relaxed/simple; bh=faqO2FdmMKajaJq4tjpw7TL4l1gi2+gSXWVN+BrhlWo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EXmzxvqfscdQWKe2jsLs8SaJKQDW5SXyYPCVLVx6V0IBFo3pYa7fYq31Uazyfp9lWnfqtbZ+d5zewj7QxZ+wfnT9WqoHM1LgFZ0qOGHtCTNI/mnAFNxracCfd5h+8l/eXDoT26fDXD4SLVNxs8826EVLnzLgtZYmM6aEDkchJrc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=cDu2FxMr; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="cDu2FxMr" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1755887802; bh=faqO2FdmMKajaJq4tjpw7TL4l1gi2+gSXWVN+BrhlWo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=cDu2FxMrmFi4f0coKZvBanPrM330IfWstYa9NuR8wwK3u7cTtOWJBK5gUzD7Oq4rl IaR/qM90IuDxc0+ke5TXmgsZ34mSsRUWiy5Yyh/Xc0zDmEjCpGwUoFYekYiN9BvcQz Wr/Cvj4J9Z2JtF6EzWhseD2+20ilZu8sGbzQHkH2Sm/rWCyRLm8d3/Mt9oGerp7r0a bpWfsJDUnejhJ2dKtqevE/cvycvwT2EAJbCvyWX8ceT0BNGANz73tOR4XqA/hfNYEf K+S6ecL5eiZtNoRrwZr7z2M/iVXVuipeZjAbSgh6/g0Xsjxy9ld8i3gzSv6hr4ViIk ioEOyt084B8MQ== Received: from [127.0.1.1] (unknown [IPv6:2600:4041:5b1a:9400:62f0:406e:ac79:4a96]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nfraprado) by bali.collaboradmins.com (Postfix) with ESMTPSA id 185C717E137E; Fri, 22 Aug 2025 20:36:35 +0200 (CEST) From: =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Date: Fri, 22 Aug 2025 14:36:11 -0400 Subject: [PATCH RFC 1/5] drm: Support post-blend color pipeline API Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-mtk-post-blend-color-pipeline-v1-1-a9446d4aca82@collabora.com> References: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> In-Reply-To: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Chun-Kuang Hu , Philipp Zabel , Matthias Brugger , AngeloGioacchino Del Regno Cc: Alex Hung , wayland-devel@lists.freedesktop.org, harry.wentland@amd.com, leo.liu@amd.com, ville.syrjala@linux.intel.com, pekka.paalanen@collabora.com, contact@emersion.fr, mwen@igalia.com, jadahl@redhat.com, sebastian.wick@redhat.com, shashank.sharma@amd.com, agoins@nvidia.com, joshua@froggi.es, mdaenzer@redhat.com, aleixpol@kde.org, xaver.hugl@gmail.com, victoria@system76.com, uma.shankar@intel.com, quic_naseer@quicinc.com, quic_cbraga@quicinc.com, quic_abhinavk@quicinc.com, marcan@marcan.st, Liviu.Dudau@arm.com, sashamcintosh@google.com, chaitanya.kumar.borah@intel.com, louis.chauvet@bootlin.com, mcanal@igalia.com, kernel@collabora.com, daniels@collabora.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= , Simona Vetter X-Mailer: b4 0.14.2 Introduce support for a post-blend color pipeline API analogous to the pre-blend color pipeline API. While the pre-blend color pipeline was configured through a COLOR_PIPELINE property attached to a drm_plane, the post-blend color pipeline is configured through a COLOR_PIPELINE property on the drm_crtc. Since colorops can now be attached to either a drm_plane or a drm_crtc, rework the helpers to account for both cases. Also introduce a new cap, DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE, to enable support for post-blend color pipelines, and prevent the now legacy GAMMA_LUT, DEGAMMA_LUT, GAMMA_LUT_SIZE and CTM properties from being exposed. Signed-off-by: N=C3=ADcolas F. R. A. Prado --- drivers/gpu/drm/drm_atomic.c | 32 ++++++-- drivers/gpu/drm/drm_atomic_uapi.c | 50 ++++++++++++- drivers/gpu/drm/drm_colorop.c | 144 +++++++++++++++++++++++++++++---= ---- drivers/gpu/drm/drm_connector.c | 1 + drivers/gpu/drm/drm_crtc.c | 77 +++++++++++++++++++ drivers/gpu/drm/drm_crtc_internal.h | 6 ++ drivers/gpu/drm/drm_ioctl.c | 7 ++ drivers/gpu/drm/drm_mode_object.c | 20 +++++ drivers/gpu/drm/drm_plane.c | 36 ++------- include/drm/drm_atomic.h | 20 +++++ include/drm/drm_atomic_uapi.h | 2 + include/drm/drm_colorop.h | 16 +++- include/drm/drm_crtc.h | 19 +++++ include/drm/drm_file.h | 7 ++ include/uapi/drm/drm.h | 16 ++++ 15 files changed, 383 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3ab32fe7fe1cbf9057c3763d979638dce013d82b..558d389d59d9a44d3cd1048ed36= 5848f62b4d62d 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -472,6 +472,8 @@ static void drm_atomic_crtc_print_state(struct drm_prin= ter *p, drm_printf(p, "\tplane_mask=3D%x\n", state->plane_mask); drm_printf(p, "\tconnector_mask=3D%x\n", state->connector_mask); drm_printf(p, "\tencoder_mask=3D%x\n", state->encoder_mask); + drm_printf(p, "\tcolor-pipeline=3D%d\n", + state->color_pipeline ? state->color_pipeline->base.id : 0); drm_printf(p, "\tmode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(&state->mode)); =20 if (crtc->funcs->atomic_print_state) @@ -617,9 +619,15 @@ drm_atomic_get_colorop_state(struct drm_atomic_state *= state, if (colorop_state) return colorop_state; =20 - ret =3D drm_modeset_lock(&colorop->plane->mutex, state->acquire_ctx); - if (ret) - return ERR_PTR(ret); + if (colorop->plane) { + ret =3D drm_modeset_lock(&colorop->plane->mutex, state->acquire_ctx); + if (ret) + return ERR_PTR(ret); + } else { + ret =3D drm_modeset_lock(&colorop->crtc->mutex, state->acquire_ctx); + if (ret) + return ERR_PTR(ret); + } =20 colorop_state =3D drm_atomic_helper_colorop_duplicate_state(colorop); if (!colorop_state) @@ -2003,11 +2011,21 @@ static void __drm_state_dump(struct drm_device *dev= , struct drm_printer *p, return; =20 list_for_each_entry(colorop, &config->colorop_list, head) { - if (take_locks) - drm_modeset_lock(&colorop->plane->mutex, NULL); + if (take_locks) { + if (colorop->plane) + drm_modeset_lock(&colorop->plane->mutex, NULL); + else + drm_modeset_lock(&colorop->crtc->mutex, NULL); + + } drm_atomic_colorop_print_state(p, colorop->state); - if (take_locks) - drm_modeset_unlock(&colorop->plane->mutex); + if (take_locks) { + if (colorop->plane) + drm_modeset_unlock(&colorop->plane->mutex); + else + drm_modeset_unlock(&colorop->crtc->mutex); + + } } =20 list_for_each_entry(plane, &config->plane_list, head) { diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic= _uapi.c index b7cc6945864274bedd21dd5b73494f9aae216888..a826758cf0b6205e2ba49734070= bc83ffb7c08df 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -287,6 +287,33 @@ drm_atomic_set_colorop_for_plane(struct drm_plane_stat= e *plane_state, } EXPORT_SYMBOL(drm_atomic_set_colorop_for_plane); =20 +/** + * drm_atomic_set_colorop_for_crtc - set colorop for crtc + * @crtc_state: atomic state object for the crtc + * @colorop: colorop to use for the crtc + * + * Helper function to select the color pipeline on a crtc by setting + * it to the first drm_colorop element of the pipeline. + */ +void +drm_atomic_set_colorop_for_crtc(struct drm_crtc_state *crtc_state, + struct drm_colorop *colorop) +{ + struct drm_crtc *crtc =3D crtc_state->crtc; + + if (colorop) + drm_dbg_atomic(crtc->dev, + "Set [COLOROP:%d] for [CRTC:%d:%s] state %p\n", + colorop->base.id, crtc->base.id, crtc->name, + crtc_state); + else + drm_dbg_atomic(crtc->dev, + "Set [NOCOLOROP] for [CRTC:%d:%s] state %p\n", + crtc->base.id, crtc->name, crtc_state); + + crtc_state->color_pipeline =3D colorop; +} +EXPORT_SYMBOL(drm_atomic_set_colorop_for_crtc); =20 /** * drm_atomic_set_crtc_for_connector - set CRTC for connector @@ -396,8 +423,8 @@ static s32 __user *get_out_fence_for_connector(struct d= rm_atomic_state *state, } =20 static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, - struct drm_crtc_state *state, struct drm_property *property, - uint64_t val) + struct drm_crtc_state *state, struct drm_file *file_priv, + struct drm_property *property, uint64_t val) { struct drm_device *dev =3D crtc->dev; struct drm_mode_config *config =3D &dev->mode_config; @@ -406,7 +433,17 @@ static int drm_atomic_crtc_set_property(struct drm_crt= c *crtc, =20 if (property =3D=3D config->prop_active) state->active =3D val; - else if (property =3D=3D config->prop_mode_id) { + else if (property =3D=3D crtc->color_pipeline_property) { + /* find DRM colorop object */ + struct drm_colorop *colorop =3D NULL; + + colorop =3D drm_colorop_find(dev, file_priv, val); + + if (val && !colorop) + return -EACCES; + + drm_atomic_set_colorop_for_crtc(state, colorop); + } else if (property =3D=3D config->prop_mode_id) { struct drm_property_blob *mode =3D drm_property_lookup_blob(dev, val); ret =3D drm_atomic_set_mode_prop_for_crtc(state, mode); @@ -487,6 +524,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val =3D 0; else if (property =3D=3D crtc->scaling_filter_property) *val =3D state->scaling_filter; + else if (property =3D=3D crtc->color_pipeline_property) + *val =3D (state->color_pipeline) ? state->color_pipeline->base.id : 0; else if (crtc->funcs->atomic_get_property) return crtc->funcs->atomic_get_property(crtc, state, property, val); else { @@ -1047,6 +1086,8 @@ int drm_atomic_get_property(struct drm_mode_object *o= bj, =20 if (colorop->plane) WARN_ON(!drm_modeset_is_locked(&colorop->plane->mutex)); + else + WARN_ON(!drm_modeset_is_locked(&colorop->crtc->mutex)); =20 ret =3D drm_atomic_colorop_get_property(colorop, colorop->state, property, val); @@ -1204,7 +1245,7 @@ int drm_atomic_set_property(struct drm_atomic_state *= state, } =20 ret =3D drm_atomic_crtc_set_property(crtc, - crtc_state, prop, prop_value); + crtc_state, file_priv, prop, prop_value); break; } case DRM_MODE_OBJECT_PLANE: { @@ -1604,6 +1645,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, state->acquire_ctx =3D &ctx; state->allow_modeset =3D !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); state->plane_color_pipeline =3D file_priv->plane_color_pipeline; + state->post_blend_color_pipeline =3D file_priv->post_blend_color_pipeline; =20 retry: copied_objs =3D 0; diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c index a1b36cd488f0a014425a9192ffe5fcc4d2c1afaa..d53de1438d23def74a77730cacd= 3651131e82cbe 100644 --- a/drivers/gpu/drm/drm_colorop.c +++ b/drivers/gpu/drm/drm_colorop.c @@ -90,8 +90,9 @@ static const struct drm_prop_enum_list drm_colorop_lut3d_= interpolation_list[] =3D =20 /* Init Helpers */ =20 -static int drm_plane_colorop_init(struct drm_device *dev, struct drm_color= op *colorop, - struct drm_plane *plane, enum drm_colorop_type type, uint32_t flags) +static int drm_common_colorop_init(struct drm_device *dev, + struct drm_colorop *colorop, + enum drm_colorop_type type, uint32_t flags) { struct drm_mode_config *config =3D &dev->mode_config; struct drm_property *prop; @@ -104,7 +105,6 @@ static int drm_plane_colorop_init(struct drm_device *de= v, struct drm_colorop *co colorop->base.properties =3D &colorop->properties; colorop->dev =3D dev; colorop->type =3D type; - colorop->plane =3D plane; colorop->next =3D NULL; =20 list_add_tail(&colorop->head, &config->colorop_list); @@ -153,6 +153,34 @@ static int drm_plane_colorop_init(struct drm_device *d= ev, struct drm_colorop *co return ret; } =20 +static int drm_crtc_colorop_init(struct drm_device *dev, + struct drm_colorop *colorop, + struct drm_crtc *crtc, + enum drm_colorop_type type, uint32_t flags) +{ + int ret; + + ret =3D drm_common_colorop_init(dev, colorop, type, flags); + + colorop->crtc =3D crtc; + + return ret; +} + +static int drm_plane_colorop_init(struct drm_device *dev, + struct drm_colorop *colorop, + struct drm_plane *plane, + enum drm_colorop_type type, uint32_t flags) +{ + int ret; + + ret =3D drm_common_colorop_init(dev, colorop, type, flags); + + colorop->plane =3D plane; + + return ret; +} + /** * drm_colorop_cleanup - Cleanup a drm_colorop object in color_pipeline * @@ -279,29 +307,16 @@ static int drm_colorop_create_data_prop(struct drm_de= vice *dev, struct drm_color return 0; } =20 -/** - * drm_plane_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT - * - * @dev: DRM device - * @colorop: The drm_colorop object to initialize - * @plane: The associated drm_plane - * @lut_size: LUT size supported by driver - * @lut1d_interpolation: 1D LUT interpolation type - * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines. - * @return zero on success, -E value on failure - */ -int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm= _colorop *colorop, - struct drm_plane *plane, uint32_t lut_size, - enum drm_colorop_lut1d_interpolation_type lut1d_interpolation, - uint32_t flags) +static int +drm_common_colorop_curve_1d_lut_init(struct drm_device *dev, + struct drm_colorop *colorop, + uint32_t lut_size, + enum drm_colorop_lut1d_interpolation_type lut1d_interpolation, + uint32_t flags) { struct drm_property *prop; int ret; =20 - ret =3D drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_LUT, f= lags); - if (ret) - return ret; - /* initialize 1D LUT only attribute */ /* LUT size */ prop =3D drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE | DRM_MOD= E_PROP_ATOMIC, @@ -333,17 +348,69 @@ int drm_plane_colorop_curve_1d_lut_init(struct drm_de= vice *dev, struct drm_color =20 return 0; } -EXPORT_SYMBOL(drm_plane_colorop_curve_1d_lut_init); =20 -int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colo= rop *colorop, - struct drm_plane *plane, uint32_t flags) +/** + * drm_crtc_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT + * + * @dev: DRM device + * @colorop: The drm_colorop object to initialize + * @crtc: The associated drm_crtc + * @lut_size: LUT size supported by driver + * @lut1d_interpolation: 1D LUT interpolation type + * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines. + * @return zero on success, -E value on failure + */ +int +drm_crtc_colorop_curve_1d_lut_init(struct drm_device *dev, + struct drm_colorop *colorop, + struct drm_crtc *crtc, uint32_t lut_size, + enum drm_colorop_lut1d_interpolation_type lut1d_interpolation, + uint32_t flags) { int ret; =20 - ret =3D drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_CTM_3X4, = flags); + ret =3D drm_crtc_colorop_init(dev, colorop, crtc, DRM_COLOROP_1D_LUT, fla= gs); if (ret) return ret; =20 + return drm_common_colorop_curve_1d_lut_init(dev, colorop, lut_size, + lut1d_interpolation, flags); +} +EXPORT_SYMBOL(drm_crtc_colorop_curve_1d_lut_init); + +/** + * drm_plane_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT + * + * @dev: DRM device + * @colorop: The drm_colorop object to initialize + * @plane: The associated drm_plane + * @lut_size: LUT size supported by driver + * @lut1d_interpolation: 1D LUT interpolation type + * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines. + * @return zero on success, -E value on failure + */ +int +drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_col= orop *colorop, + struct drm_plane *plane, uint32_t lut_size, + enum drm_colorop_lut1d_interpolation_type lut1d_interpolation, + uint32_t flags) +{ + int ret; + + ret =3D drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_LUT, f= lags); + if (ret) + return ret; + + return drm_common_colorop_curve_1d_lut_init(dev, colorop, lut_size, + lut1d_interpolation, flags); +} +EXPORT_SYMBOL(drm_plane_colorop_curve_1d_lut_init); + +static int drm_common_colorop_ctm_3x4_init(struct drm_device *dev, struct = drm_colorop *colorop, + uint32_t flags) +{ + int ret; + ret =3D drm_colorop_create_data_prop(dev, colorop); if (ret) return ret; @@ -352,6 +419,31 @@ int drm_plane_colorop_ctm_3x4_init(struct drm_device *= dev, struct drm_colorop *c =20 return 0; } + +int drm_crtc_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_color= op *colorop, + struct drm_crtc *crtc, uint32_t flags) +{ + int ret; + + ret =3D drm_crtc_colorop_init(dev, colorop, crtc, DRM_COLOROP_CTM_3X4, fl= ags); + if (ret) + return ret; + + return drm_common_colorop_ctm_3x4_init(dev, colorop, flags); +} +EXPORT_SYMBOL(drm_crtc_colorop_ctm_3x4_init); + +int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colo= rop *colorop, + struct drm_plane *plane, uint32_t flags) +{ + int ret; + + ret =3D drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_CTM_3X4, = flags); + if (ret) + return ret; + + return drm_common_colorop_ctm_3x4_init(dev, colorop, flags); +} EXPORT_SYMBOL(drm_plane_colorop_ctm_3x4_init); =20 /** diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connecto= r.c index 4d6dc9ebfdb5bc730b1aff7a184448af7b93f078..f58cfd2131139ff3e613adc4dbb= 9ddbedf724dc7 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -3440,6 +3440,7 @@ int drm_mode_getconnector(struct drm_device *dev, voi= d *data, */ ret =3D drm_mode_object_get_properties(&connector->base, file_priv->atomi= c, file_priv->plane_color_pipeline, + file_priv->post_blend_color_pipeline, (uint32_t __user *)(unsigned long)(out_resp->props_ptr), (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), &out_resp->count_props); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 46655339003db2a1b43441434839e26f61d79b4e..94238163ff1254c721df39c030b= c99a31d3bb92a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -959,3 +959,80 @@ bool drm_crtc_in_clone_mode(struct drm_crtc_state *crt= c_state) return hweight32(crtc_state->encoder_mask) > 1; } EXPORT_SYMBOL(drm_crtc_in_clone_mode); + +struct drm_property * +drm_common_create_color_pipeline_property(struct drm_device *dev, struct d= rm_mode_object *obj, + const struct drm_prop_enum_list *pipelines, + int num_pipelines) +{ + struct drm_prop_enum_list *all_pipelines; + struct drm_property *prop; + int len =3D 0; + int i; + + all_pipelines =3D kcalloc(num_pipelines + 1, + sizeof(*all_pipelines), + GFP_KERNEL); + + if (!all_pipelines) { + drm_err(dev, "failed to allocate color pipeline\n"); + return ERR_PTR(-ENOMEM); + } + + /* Create default Bypass color pipeline */ + all_pipelines[len].type =3D 0; + all_pipelines[len].name =3D "Bypass"; + len++; + + /* Add all other color pipelines */ + for (i =3D 0; i < num_pipelines; i++, len++) { + all_pipelines[len].type =3D pipelines[i].type; + all_pipelines[len].name =3D pipelines[i].name; + } + + prop =3D drm_property_create_enum(dev, DRM_MODE_PROP_ATOMIC, + "COLOR_PIPELINE", + all_pipelines, len); + if (IS_ERR(prop)) { + kfree(all_pipelines); + return prop; + } + + drm_object_attach_property(obj, prop, 0); + + kfree(all_pipelines); + return prop; +} + +/** + * drm_crtc_create_color_pipeline_property - create a new color pipeline + * property + * + * @crtc: drm CRTC + * @pipelines: list of pipelines + * @num_pipelines: number of pipelines + * + * Create the COLOR_PIPELINE CRTC property to specify color pipelines on + * the CRTC. + * + * RETURNS: + * Zero for success or -errno + */ +int drm_crtc_create_color_pipeline_property(struct drm_crtc *crtc, + const struct drm_prop_enum_list *pipelines, + int num_pipelines) +{ + struct drm_property *prop; + + prop =3D drm_common_create_color_pipeline_property(crtc->dev, + &crtc->base, + pipelines, + num_pipelines); + if (IS_ERR(prop)) + return PTR_ERR(prop); + + crtc->color_pipeline_property =3D prop; + + return 0; +} +EXPORT_SYMBOL(drm_crtc_create_color_pipeline_property); diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc= _internal.h index c094092296448093c5cd192ecdc8ea9a50769c90..c53f154e5392a10c326c844b732= 1666275f9ac02 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -35,6 +35,7 @@ #ifndef __DRM_CRTC_INTERNAL_H__ #define __DRM_CRTC_INTERNAL_H__ =20 +#include #include #include =20 @@ -79,6 +80,10 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, int drm_crtc_register_all(struct drm_device *dev); void drm_crtc_unregister_all(struct drm_device *dev); int drm_crtc_force_disable(struct drm_crtc *crtc); +struct drm_property * +drm_common_create_color_pipeline_property(struct drm_device *dev, struct d= rm_mode_object *obj, + const struct drm_prop_enum_list *pipelines, + int num_pipelines); =20 struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc); =20 @@ -164,6 +169,7 @@ void drm_mode_object_unregister(struct drm_device *dev, struct drm_mode_object *object); int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomi= c, bool plane_color_pipeline, + bool post_blend_color_pipeline, uint32_t __user *prop_ptr, uint64_t __user *prop_values, uint32_t *arg_count_props); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index ff193155129e7e863888d8958458978566b144f8..2c81f63fee428ca85f3c626d892= ea6097b964e88 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -380,6 +380,13 @@ drm_setclientcap(struct drm_device *dev, void *data, s= truct drm_file *file_priv) return -EINVAL; file_priv->plane_color_pipeline =3D req->value; break; + case DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE: + if (!file_priv->atomic) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->post_blend_color_pipeline =3D req->value; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_o= bject.c index b45d501b10c868c6d9b7a5a8760eadbd7b372a6a..c9e20d12e8fd311f71b9d6bc8d5= 75624751d33ad 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -388,6 +388,7 @@ EXPORT_SYMBOL(drm_object_property_get_default_value); /* helper for getconnector and getproperties ioctls */ int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomi= c, bool plane_color_pipeline, + bool post_blend_color_pipeline, uint32_t __user *prop_ptr, uint64_t __user *prop_values, uint32_t *arg_count_props) @@ -416,6 +417,24 @@ int drm_mode_object_get_properties(struct drm_mode_obj= ect *obj, bool atomic, continue; } =20 + if (post_blend_color_pipeline && obj->type =3D=3D DRM_MODE_OBJECT_CRTC) { + struct drm_crtc *crtc =3D obj_to_crtc(obj); + struct drm_mode_config mode_config =3D crtc->dev->mode_config; + + if (prop =3D=3D mode_config.gamma_lut_property || + prop =3D=3D mode_config.degamma_lut_property || + prop =3D=3D mode_config.gamma_lut_size_property || + prop =3D=3D mode_config.ctm_property) + continue; + } + + if (!post_blend_color_pipeline && obj->type =3D=3D DRM_MODE_OBJECT_CRTC)= { + struct drm_crtc *crtc =3D obj_to_crtc(obj); + + if (prop =3D=3D crtc->color_pipeline_property) + continue; + } + if (*arg_count_props > count) { ret =3D __drm_object_property_get_value(obj, prop, &val); if (ret) @@ -475,6 +494,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device= *dev, void *data, =20 ret =3D drm_mode_object_get_properties(obj, file_priv->atomic, file_priv->plane_color_pipeline, + file_priv->post_blend_color_pipeline, (uint32_t __user *)(unsigned long)(arg->props_ptr), (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), &arg->count_props); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index f6cfa8ac090c7bc49c7f276993bba7e9800da140..60dbfcab495600dd44c15260a1f= a6135db59c6e2 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1839,43 +1839,17 @@ int drm_plane_create_color_pipeline_property(struct= drm_plane *plane, const struct drm_prop_enum_list *pipelines, int num_pipelines) { - struct drm_prop_enum_list *all_pipelines; struct drm_property *prop; - int len =3D 0; - int i; - - all_pipelines =3D kcalloc(num_pipelines + 1, - sizeof(*all_pipelines), - GFP_KERNEL); - - if (!all_pipelines) { - drm_err(plane->dev, "failed to allocate color pipeline\n"); - return -ENOMEM; - } =20 - /* Create default Bypass color pipeline */ - all_pipelines[len].type =3D 0; - all_pipelines[len].name =3D "Bypass"; - len++; - - /* Add all other color pipelines */ - for (i =3D 0; i < num_pipelines; i++, len++) { - all_pipelines[len].type =3D pipelines[i].type; - all_pipelines[len].name =3D pipelines[i].name; - } - - prop =3D drm_property_create_enum(plane->dev, DRM_MODE_PROP_ATOMIC, - "COLOR_PIPELINE", - all_pipelines, len); - if (IS_ERR(prop)) { - kfree(all_pipelines); + prop =3D drm_common_create_color_pipeline_property(plane->dev, + &plane->base, + pipelines, + num_pipelines); + if (IS_ERR(prop)) return PTR_ERR(prop); - } =20 - drm_object_attach_property(&plane->base, prop, 0); plane->color_pipeline_property =3D prop; =20 - kfree(all_pipelines); return 0; } EXPORT_SYMBOL(drm_plane_create_color_pipeline_property); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 678708df9cdb90b4266127193a92183069f18688..8c42c584aefbf0034b2163d9053= 8e80099b0dadb 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -482,6 +482,26 @@ struct drm_atomic_state { */ bool plane_color_pipeline : 1; =20 + /** + * @post_blend_color_pipeline: + * + * Indicates whether this atomic state originated with a client that + * set the DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE. + * + * Drivers and helper functions should use this to ignore legacy + * properties that are incompatible with the drm_crtc COLOR_PIPELINE + * behavior, such as: + * + * - GAMMA_LUT + * - DEGAMMA_LUT + * - GAMMA_LUT_SIZE + * - CTM + * + * or any other driver-specific properties that might affect pixel + * values. + */ + bool post_blend_color_pipeline : 1; + /** * @colorops: * diff --git a/include/drm/drm_atomic_uapi.h b/include/drm/drm_atomic_uapi.h index 4363155233267b93767c895fa6085544e2277442..4dc191f6f929d73deee9812025c= 48275a33cf770 100644 --- a/include/drm/drm_atomic_uapi.h +++ b/include/drm/drm_atomic_uapi.h @@ -52,6 +52,8 @@ void drm_atomic_set_fb_for_plane(struct drm_plane_state *= plane_state, struct drm_framebuffer *fb); void drm_atomic_set_colorop_for_plane(struct drm_plane_state *plane_state, struct drm_colorop *colorop); +void drm_atomic_set_colorop_for_crtc(struct drm_crtc_state *crtc_state, + struct drm_colorop *colorop); int __must_check drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, struct drm_crtc *crtc); diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h index d61c6c40e47162cb8b1e7db58b6746c43ac5d202..710a6199ebc5498a3f664de39ea= 07dbc95944eb7 100644 --- a/include/drm/drm_colorop.h +++ b/include/drm/drm_colorop.h @@ -206,10 +206,16 @@ struct drm_colorop { /** * @plane: * - * The plane on which the colorop sits. A drm_colorop is always unique - * to a plane. + * The plane on which the colorop sits if it is a pre-blend colorop. + * In this case it is unique to the plane. + * + * @crtc: + * + * The CRTC on which the colorop sits if it is a post-blend colorop. + * In this case it is unique to the CRTC. */ struct drm_plane *plane; + struct drm_crtc *crtc; =20 /** * @state: @@ -370,6 +376,10 @@ static inline struct drm_colorop *drm_colorop_find(str= uct drm_device *dev, =20 void drm_colorop_pipeline_destroy(struct drm_device *dev); =20 +int drm_crtc_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_= colorop *colorop, + struct drm_crtc *crtc, uint32_t lut_size, + enum drm_colorop_lut1d_interpolation_type lut1d_interpolation, + uint32_t flags); int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_col= orop *colorop, struct drm_plane *plane, u64 supported_tfs, uint32_t flags); int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm= _colorop *colorop, @@ -378,6 +388,8 @@ int drm_plane_colorop_curve_1d_lut_init(struct drm_devi= ce *dev, struct drm_color uint32_t flags); int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colo= rop *colorop, struct drm_plane *plane, uint32_t flags); +int drm_crtc_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_color= op *colorop, + struct drm_crtc *crtc, uint32_t flags); int drm_plane_colorop_mult_init(struct drm_device *dev, struct drm_colorop= *colorop, struct drm_plane *plane, uint32_t flags); int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_coloro= p *colorop, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index caa56e039da2a748cf40ebf45b37158acda439d9..df03637ca25abd45e96b5944229= 297f776fd046d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -274,6 +274,14 @@ struct drm_crtc_state { */ struct drm_property_blob *gamma_lut; =20 + /** + * @color_pipeline: + * + * The first colorop of the active color pipeline, or NULL, if no + * color pipeline is active. + */ + struct drm_colorop *color_pipeline; + /** * @target_vblank: * @@ -1088,6 +1096,14 @@ struct drm_crtc { */ struct drm_property *scaling_filter_property; =20 + /** + * @color_pipeline_property: + * + * Optional "COLOR_PIPELINE" enum property for specifying + * a color pipeline to use on the CRTC. + */ + struct drm_property *color_pipeline_property; + /** * @state: * @@ -1323,5 +1339,8 @@ static inline struct drm_crtc *drm_crtc_find(struct d= rm_device *dev, =20 int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc, unsigned int supported_filters); +int drm_crtc_create_color_pipeline_property(struct drm_crtc *crtc, + const struct drm_prop_enum_list *pipelines, + int num_pipelines); bool drm_crtc_in_clone_mode(struct drm_crtc_state *crtc_state); #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 1a3018e4a537b3341acb50187d47371f6b781b9d..42b9a43baa18079af8ec2ea5b14= 84b23c497beb0 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -213,6 +213,13 @@ struct drm_file { */ bool plane_color_pipeline; =20 + /** + * @post_blend_color_pipeline: + * + * True if client understands post-blend color pipelines + */ + bool post_blend_color_pipeline; + /** * @was_master: * diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 27cc159c1d275c7a7fe057840ef792f30a582bb7..1191b142ebaa5478376308f169f= 9ce8591580d9d 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -921,6 +921,22 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE 7 =20 +/** + * DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE + * + * If set to 1 the DRM core will allow setting the COLOR_PIPELINE + * property on a &drm_crtc, as well as drm_colorop properties. + * + * Setting of these crtc properties will be rejected when this client + * cap is set: + * - GAMMA_LUT + * - DEGAMMA_LUT + * - CTM + * + * The client must enable &DRM_CLIENT_CAP_ATOMIC first. + */ +#define DRM_CLIENT_CAP_POST_BLEND_COLOR_PIPELINE 8 + /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; --=20 2.47.2 From nobody Fri Oct 3 23:02:08 2025 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AC252C0275 for ; Fri, 22 Aug 2025 18:36:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887812; cv=none; b=TgX0e9S9qPJYZ3wuICvmeT2ot20/3tkUh+/shoQreDMPSfbgBHz6v5sQrEUy0SpyB6IUDJjzK06SWC3fjimv0EZ68IEKvceTxMTKcpW3LpJ4cRR3joMeo3rGZblnrqCqm4qBZELwRKInQw7h4y/iIzfY9mDpd0C27Q0+s3S3gGE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887812; c=relaxed/simple; bh=emo1Y+He1rL7+g/lnBKo9KHUxgoj16EF+fdtTkETCdg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=d/HXo/nLMWFMrrCrdLV/FZjpsiYD0nUtleSe/sZtZH9Il5T78fjosdajjkFTRiiNkjvxxfTTIUrCaoUQtAtcq44lrPRlmM2+8+xS47bQvbe0jFxLcWkmmKO+ljF1NpVSjvp2/bA/hQQ75VZ6PfwLZ9iNHMPeyT4/WD4xJ7OQg2k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=FwwFLtVt; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="FwwFLtVt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1755887809; bh=emo1Y+He1rL7+g/lnBKo9KHUxgoj16EF+fdtTkETCdg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=FwwFLtVtG4Bv7Sw2mnor1fBatS0kOibcyamFMwJSoKlggaHCcZxAsUURHcDEsv2CQ ghmtO83Z4zQNVI96GrqPFgHO5v6bRsIrx4w3+44deJ2LoagxGmoKJ1nChvoCmQP28Q rqpl1eJnGVep0DoBXXuS/lcYPRAWTd+55uWemfEd+xlAoxwHN5a3qbhuRyt+GzBZUS Z68TujGclw69uzR4Cc3cya1YXAOgqoB57yCiUfxAaTPSEYcLXrAKQKXZRs8KDBYxDF 9tEQ4B/ng2NGDNbUIydt5NeSwl/0Qid/tn2sl//x7KN0wR8QctScU+VThlnBBNVVLQ jdQ/+AwVtPjvw== Received: from [127.0.1.1] (unknown [IPv6:2600:4041:5b1a:9400:62f0:406e:ac79:4a96]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nfraprado) by bali.collaboradmins.com (Postfix) with ESMTPSA id 2737517E159C; Fri, 22 Aug 2025 20:36:43 +0200 (CEST) From: =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Date: Fri, 22 Aug 2025 14:36:12 -0400 Subject: [PATCH RFC 2/5] drm/colorop: Export drm_colorop_cleanup() so drivers can extend it Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-mtk-post-blend-color-pipeline-v1-2-a9446d4aca82@collabora.com> References: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> In-Reply-To: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Chun-Kuang Hu , Philipp Zabel , Matthias Brugger , AngeloGioacchino Del Regno Cc: Alex Hung , wayland-devel@lists.freedesktop.org, harry.wentland@amd.com, leo.liu@amd.com, ville.syrjala@linux.intel.com, pekka.paalanen@collabora.com, contact@emersion.fr, mwen@igalia.com, jadahl@redhat.com, sebastian.wick@redhat.com, shashank.sharma@amd.com, agoins@nvidia.com, joshua@froggi.es, mdaenzer@redhat.com, aleixpol@kde.org, xaver.hugl@gmail.com, victoria@system76.com, uma.shankar@intel.com, quic_naseer@quicinc.com, quic_cbraga@quicinc.com, quic_abhinavk@quicinc.com, marcan@marcan.st, Liviu.Dudau@arm.com, sashamcintosh@google.com, chaitanya.kumar.borah@intel.com, louis.chauvet@bootlin.com, mcanal@igalia.com, kernel@collabora.com, daniels@collabora.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= , Simona Vetter X-Mailer: b4 0.14.2 Export drm_colorop_cleanup() so drivers subclassing drm_colorop can reuse this function in subclass cleanup routines. Signed-off-by: N=C3=ADcolas F. R. A. Prado Reviewed-by: Louis Chauvet --- drivers/gpu/drm/drm_colorop.c | 3 ++- include/drm/drm_colorop.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c index d53de1438d23def74a77730cacd3651131e82cbe..8a27861a367ab321d45835099f4= 38ee5e2abd709 100644 --- a/drivers/gpu/drm/drm_colorop.c +++ b/drivers/gpu/drm/drm_colorop.c @@ -186,7 +186,7 @@ static int drm_plane_colorop_init(struct drm_device *de= v, * * @colorop: The drm_colorop object to be cleaned */ -static void drm_colorop_cleanup(struct drm_colorop *colorop) +void drm_colorop_cleanup(struct drm_colorop *colorop) { struct drm_device *dev =3D colorop->dev; struct drm_mode_config *config =3D &dev->mode_config; @@ -201,6 +201,7 @@ static void drm_colorop_cleanup(struct drm_colorop *col= orop) =20 kfree(colorop->state); } +EXPORT_SYMBOL(drm_colorop_cleanup); =20 /** * drm_colorop_pipeline_destroy - Helper for color pipeline destruction diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h index 710a6199ebc5498a3f664de39ea07dbc95944eb7..158c2b8f775b99fd0a0efa03f2c= 019f14a9bc8b3 100644 --- a/include/drm/drm_colorop.h +++ b/include/drm/drm_colorop.h @@ -374,6 +374,7 @@ static inline struct drm_colorop *drm_colorop_find(stru= ct drm_device *dev, return mo ? obj_to_colorop(mo) : NULL; } =20 +void drm_colorop_cleanup(struct drm_colorop *colorop); void drm_colorop_pipeline_destroy(struct drm_device *dev); =20 int drm_crtc_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_= colorop *colorop, --=20 2.47.2 From nobody Fri Oct 3 23:02:08 2025 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A6682BF3E2 for ; Fri, 22 Aug 2025 18:36:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887819; cv=none; b=Zs9VPJyTP9xnQEIrWvE9daaOf9NgwCh4Vw6wTYP+r6H0GtsMI5b5htgpGjgmHgBTg0dXDV1l8zdt1bZaIH77YRhWuyVIBjXkk9lBgKr7MTPRBxGuOY6mYZ6X4QDEv+kkkFCyE3sNBIFYfp5l9C5wfz/aryaAIRQXSR3MqQS/YIg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887819; c=relaxed/simple; bh=MOIF2cB0LO1VICpQHMRer6AFZ1UnHXVMR9XETwXOMRM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=r9H08qQqa+cxxko//vxbfZARwXGMvEWPVNBgf3NwToQnIcVM6asgbD7o5WcUs8Xf6jbWHqmOMGmYT8cU7b9tVomM2SDoiYwJCTPd8IQrvmztMhK7v8kOSKWtruzZpvFwuE8MyBTcdAt83yOgcfrlWil9TPL3nPWKvK9Th6hjhA8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=NiFxcSuq; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="NiFxcSuq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1755887816; bh=MOIF2cB0LO1VICpQHMRer6AFZ1UnHXVMR9XETwXOMRM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=NiFxcSuqwxNiT6GFfDQ27KovnLNh1DIcuvMmlCQI1heIPELBKibZ5Yp+wVXRoCk5N hNRIZtxiXc6K+RCtpmeE7rt/HrgbEQH22+D4gvaQFkRGZpXM1EmQWl1DO3ki91ANh0 pPf8x+afQuImJaCGqG20ul7k6fO2rj/pnoekFEyIeW7Y0JeuqVsco3MDsJk1ZsXChT ZHwum+/raAF+PZ5C2tGaAwJBEbrFS9YmpAKkxOMBsTATwD2uFkG/j1b9Kk0T90mZwo FzmglwfgyWTlQwDI6Vighg+9TnM4TneLFRm5A/EjpCqUXvWquX6utPJVuRU0Hr9kB3 IEj3RoaFAipZg== Received: from [127.0.1.1] (unknown [IPv6:2600:4041:5b1a:9400:62f0:406e:ac79:4a96]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nfraprado) by bali.collaboradmins.com (Postfix) with ESMTPSA id 9FB2417E15AB; Fri, 22 Aug 2025 20:36:49 +0200 (CEST) From: =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Date: Fri, 22 Aug 2025 14:36:13 -0400 Subject: [PATCH RFC 3/5] drm/mediatek: Support post-blend colorops for gamma and ctm Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-mtk-post-blend-color-pipeline-v1-3-a9446d4aca82@collabora.com> References: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> In-Reply-To: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Chun-Kuang Hu , Philipp Zabel , Matthias Brugger , AngeloGioacchino Del Regno Cc: Alex Hung , wayland-devel@lists.freedesktop.org, harry.wentland@amd.com, leo.liu@amd.com, ville.syrjala@linux.intel.com, pekka.paalanen@collabora.com, contact@emersion.fr, mwen@igalia.com, jadahl@redhat.com, sebastian.wick@redhat.com, shashank.sharma@amd.com, agoins@nvidia.com, joshua@froggi.es, mdaenzer@redhat.com, aleixpol@kde.org, xaver.hugl@gmail.com, victoria@system76.com, uma.shankar@intel.com, quic_naseer@quicinc.com, quic_cbraga@quicinc.com, quic_abhinavk@quicinc.com, marcan@marcan.st, Liviu.Dudau@arm.com, sashamcintosh@google.com, chaitanya.kumar.borah@intel.com, louis.chauvet@bootlin.com, mcanal@igalia.com, kernel@collabora.com, daniels@collabora.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= , Simona Vetter X-Mailer: b4 0.14.2 Allow configuring the gamma and ccorr blocks through the post-blend color pipeline API instead of the GAMMA_LUT and CTM properties. In order to achieve this, initialize the color pipeline property and colorops on the CRTC based on the DDP components available in the CRTC path. Then introduce a struct mtk_drm_colorop that extends drm_colorop and tracks the mtk_ddp_comp that implements it in hardware, and include new ddp_comp helper functions for setting gamma and ctm through the new API. These helpers will then be called during commit flush for every updated colorop if the DRM client supports the post-blend color pipeline API. Signed-off-by: N=C3=ADcolas F. R. A. Prado --- drivers/gpu/drm/mediatek/mtk_crtc.c | 211 ++++++++++++++++++++++++++++= +++- drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 2 + 2 files changed, 208 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek= /mtk_crtc.c index bc7527542fdc6fb89fc36794cee7d6dc26f7dcce..80ed061de1af31916d814f29f91= 11973cffd10dd 100644 --- a/drivers/gpu/drm/mediatek/mtk_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_crtc.c @@ -82,6 +82,12 @@ struct mtk_crtc_state { unsigned int pending_vrefresh; }; =20 +struct mtk_drm_colorop { + struct drm_colorop colorop; + struct mtk_ddp_comp *comp; + uint32_t data_id; +}; + static inline struct mtk_crtc *to_mtk_crtc(struct drm_crtc *c) { return container_of(c, struct mtk_crtc, base); @@ -92,6 +98,11 @@ static inline struct mtk_crtc_state *to_mtk_crtc_state(s= truct drm_crtc_state *s) return container_of(s, struct mtk_crtc_state, base); } =20 +static inline struct mtk_drm_colorop *to_mtk_colorop(struct drm_colorop *c= olorop) +{ + return container_of(colorop, struct mtk_drm_colorop, colorop); +} + static void mtk_crtc_finish_page_flip(struct mtk_crtc *mtk_crtc) { struct drm_crtc *crtc =3D &mtk_crtc->base; @@ -125,6 +136,19 @@ static void mtk_drm_finish_page_flip(struct mtk_crtc *= mtk_crtc) spin_unlock_irqrestore(&mtk_crtc->config_lock, flags); } =20 +static void mtk_drm_colorop_pipeline_destroy(struct drm_device *dev) +{ + struct drm_mode_config *config =3D &dev->mode_config; + struct drm_colorop *colorop, *next; + struct mtk_drm_colorop *mtk_colorop; + + list_for_each_entry_safe(colorop, next, &config->colorop_list, head) { + drm_colorop_cleanup(colorop); + mtk_colorop =3D to_mtk_colorop(colorop); + kfree(mtk_colorop); + } +} + static void mtk_crtc_destroy(struct drm_crtc *crtc) { struct mtk_crtc *mtk_crtc =3D to_mtk_crtc(crtc); @@ -146,6 +170,8 @@ static void mtk_crtc_destroy(struct drm_crtc *crtc) mtk_ddp_comp_unregister_vblank_cb(comp); } =20 + mtk_drm_colorop_pipeline_destroy(crtc->dev); + drm_crtc_cleanup(crtc); } =20 @@ -854,20 +880,103 @@ static void mtk_crtc_atomic_begin(struct drm_crtc *c= rtc, } } =20 +static bool colorop_data_update_flush_status(struct drm_colorop_state *col= orop_state) +{ + struct drm_colorop *colorop =3D colorop_state->colorop; + struct mtk_drm_colorop *mtk_colorop =3D to_mtk_colorop(colorop); + struct drm_property_blob *data_blob =3D colorop_state->data; + uint32_t data_id =3D colorop_state->bypass ? 0 : data_blob->base.id; + bool needs_flush =3D mtk_colorop->data_id !=3D data_id; + + mtk_colorop->data_id =3D data_id; + + return needs_flush; +} + +static void mtk_crtc_ddp_comp_apply_colorop(struct drm_colorop_state *colo= rop_state) +{ + struct drm_colorop *colorop =3D colorop_state->colorop; + struct mtk_drm_colorop *mtk_colorop =3D to_mtk_colorop(colorop); + struct drm_property_blob *data_blob =3D colorop_state->data; + struct mtk_ddp_comp *ddp_comp =3D mtk_colorop->comp; + struct drm_color_ctm_3x4 *ctm =3D NULL; + struct drm_color_lut32 *lut =3D NULL; + + switch (colorop->type) { + case DRM_COLOROP_1D_LUT: + if (!colorop_data_update_flush_status(colorop_state)) + return; + + if (!colorop_state->bypass) + lut =3D (struct drm_color_lut32 *)data_blob->data; + + ddp_comp->funcs->gamma_set_color_pipeline(ddp_comp->dev, lut); + break; + case DRM_COLOROP_CTM_3X4: + if (!colorop_data_update_flush_status(colorop_state)) + return; + + if (!colorop_state->bypass) + ctm =3D (struct drm_color_ctm_3x4 *)data_blob->data; + + ddp_comp->funcs->ctm_set_color_pipeline(ddp_comp->dev, ctm); + break; + default: + /* If this happens the driver is broken */ + drm_WARN(colorop->dev, 1, + "Trying to atomic flush COLOROP of type unsupported by driver: %d\n", + colorop->type); + break; + } +} + static void mtk_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct mtk_crtc *mtk_crtc =3D to_mtk_crtc(crtc); + struct drm_colorop_state *new_colorop_state; + struct drm_colorop *colorop; int i; =20 - if (crtc->state->color_mgmt_changed) - for (i =3D 0; i < mtk_crtc->ddp_comp_nr; i++) { - mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); - mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state); - } + if (state->post_blend_color_pipeline) { + for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) + mtk_crtc_ddp_comp_apply_colorop(new_colorop_state); + } else { + if (crtc->state->color_mgmt_changed) + for (i =3D 0; i < mtk_crtc->ddp_comp_nr; i++) { + mtk_ddp_gamma_set(mtk_crtc->ddp_comp[i], crtc->state); + mtk_ddp_ctm_set(mtk_crtc->ddp_comp[i], crtc->state); + } + } mtk_crtc_update_config(mtk_crtc, !!mtk_crtc->event); } =20 +static int mtk_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_colorop_state *new_colorop_state; + struct drm_colorop *colorop; + int i; + + for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { + switch (colorop->type) { + case DRM_COLOROP_1D_LUT: + case DRM_COLOROP_CTM_3X4: + if (!new_colorop_state->bypass && !new_colorop_state->data) { + drm_dbg_atomic(crtc->dev, + "Missing required DATA property for COLOROP:%d\n", + colorop->base.id); + return -EINVAL; + } + break; + default: + break; + } + } + + return 0; +} + static const struct drm_crtc_funcs mtk_crtc_funcs =3D { .set_config =3D drm_atomic_helper_set_config, .page_flip =3D drm_atomic_helper_page_flip, @@ -885,6 +994,7 @@ static const struct drm_crtc_helper_funcs mtk_crtc_help= er_funcs =3D { .mode_valid =3D mtk_crtc_mode_valid, .atomic_begin =3D mtk_crtc_atomic_begin, .atomic_flush =3D mtk_crtc_atomic_flush, + .atomic_check =3D mtk_crtc_atomic_check, .atomic_enable =3D mtk_crtc_atomic_enable, .atomic_disable =3D mtk_crtc_atomic_disable, }; @@ -987,6 +1097,95 @@ struct device *mtk_crtc_dma_dev_get(struct drm_crtc *= crtc) return mtk_crtc->dma_dev; } =20 +#define MAX_COLOR_PIPELINE_OPS 2 +#define MAX_COLOR_PIPELINES 1 + +static int mtk_colorop_init(struct mtk_crtc *mtk_crtc, + struct mtk_drm_colorop *mtk_colorop, + struct mtk_ddp_comp *ddp_comp) +{ + struct drm_colorop *colorop =3D &mtk_colorop->colorop; + int ret =3D 0; + + if (ddp_comp->funcs->gamma_set_color_pipeline) { + unsigned int lut_sz =3D mtk_ddp_gamma_get_lut_size(ddp_comp); + + ret =3D drm_crtc_colorop_curve_1d_lut_init(mtk_crtc->base.dev, colorop, + &mtk_crtc->base, + lut_sz, + DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + } else if (ddp_comp->funcs->ctm_set_color_pipeline) { + ret =3D drm_crtc_colorop_ctm_3x4_init(mtk_crtc->base.dev, + colorop, + &mtk_crtc->base, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + } + + mtk_colorop->comp =3D ddp_comp; + + return ret; +} + +static int mtk_crtc_init_post_blend_color_pipeline(struct mtk_crtc *mtk_cr= tc, + unsigned int gamma_lut_size) +{ + struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES]; + struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS]; + struct mtk_drm_colorop *mtk_colorop; + unsigned int num_pipelines =3D 0; + unsigned int op_idx =3D 0; + int ret; + + memset(ops, 0, sizeof(ops)); + + for (unsigned int i =3D 0; + i < mtk_crtc->ddp_comp_nr && op_idx < MAX_COLOR_PIPELINE_OPS; + i++) { + struct mtk_ddp_comp *ddp_comp =3D mtk_crtc->ddp_comp[i]; + + if (!(ddp_comp->funcs->gamma_set_color_pipeline || + ddp_comp->funcs->ctm_set_color_pipeline)) + continue; + + mtk_colorop =3D kzalloc(sizeof(struct mtk_drm_colorop), GFP_KERNEL); + if (!mtk_colorop) { + ret =3D -ENOMEM; + goto cleanup; + } + + ops[op_idx] =3D &mtk_colorop->colorop; + + ret =3D mtk_colorop_init(mtk_crtc, mtk_colorop, ddp_comp); + if (ret) + goto cleanup; + + if (op_idx > 0) + drm_colorop_set_next_property(ops[op_idx-1], ops[op_idx]); + + op_idx++; + } + + if (op_idx > 0) { + pipelines[0].type =3D ops[0]->base.id; + pipelines[0].name =3D kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]-= >base.id); + num_pipelines =3D 1; + } + + /* Create COLOR_PIPELINE property and attach */ + drm_crtc_create_color_pipeline_property(&mtk_crtc->base, pipelines, num_p= ipelines); + + return 0; + +cleanup: + if (ret =3D=3D -ENOMEM) + drm_err(mtk_crtc->base.dev, "KMS: Failed to allocate colorop\n"); + + mtk_drm_colorop_pipeline_destroy(mtk_crtc->base.dev); + + return ret; +} + int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path, unsigned int path_len, int priv_data_index, const struct mtk_drm_route *conn_routes, @@ -1103,6 +1302,8 @@ int mtk_crtc_create(struct drm_device *drm_dev, const= unsigned int *path, if (ret < 0) return ret; =20 + mtk_crtc_init_post_blend_color_pipeline(mtk_crtc, gamma_lut_size); + if (gamma_lut_size) drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/medi= atek/mtk_ddp_comp.h index 7289b3dcf22f22f344016beee0c7c144cf7b93c8..554c3cc8ad7b266b8b8eee74ceb= 8f7383fe2f8df 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h @@ -75,10 +75,12 @@ struct mtk_ddp_comp_funcs { unsigned int (*gamma_get_lut_size)(struct device *dev); void (*gamma_set)(struct device *dev, struct drm_crtc_state *state); + void (*gamma_set_color_pipeline)(struct device *dev, struct drm_color_lut= 32 *lut); void (*bgclr_in_on)(struct device *dev); void (*bgclr_in_off)(struct device *dev); void (*ctm_set)(struct device *dev, struct drm_crtc_state *state); + void (*ctm_set_color_pipeline)(struct device *dev, struct drm_color_ctm_3= x4 *ctm); struct device * (*dma_dev_get)(struct device *dev); u32 (*get_blend_modes)(struct device *dev); const u32 *(*get_formats)(struct device *dev); --=20 2.47.2 From nobody Fri Oct 3 23:02:08 2025 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2126A2C0F6F for ; Fri, 22 Aug 2025 18:37:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887826; cv=none; b=Dxcj/Z0XWjKre+PLar3tw+uCt29EcEJs5ol2CdAayxkkrrj06MwXYlBYrr4wLdvzMo+JEweEo7uP12OHwzhEW9wmmesmzpabfi2S8EJBiwaVVNDq6QLpWtFkaQUoJjD2nSazoLugQvEM76bqCaKTAIRTc1qL5La7RmPe7kpX/iU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887826; c=relaxed/simple; bh=vr9BwkfpPl2aezdbMUSWAGBDTvysFxMaRfBw43Yz+S8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ah02nFRp4ImPFvGBnt/+Q2/Grl9yVAiuYTx7r2/TcTlhJixg1iScYWCO1fwh8YCC8PiI5zpxr8rsuF8ur+8K6kNkphDft/eOgO6hXqhwWj2vgWtcOwbYoWIHGK3hYWwsPEK1gWlLNJ5Ms6j9Ppm78CbIk2gxsMchB7c9PdCZLxk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=pRppNzg5; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="pRppNzg5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1755887822; bh=vr9BwkfpPl2aezdbMUSWAGBDTvysFxMaRfBw43Yz+S8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=pRppNzg5s4uapPjn7YtBbfZGGZIxmaNVknnJRDYFOPwrbTtTsQozz/rDRL8rPzVIM E24A4TrF/3enIMPnbB6oP8CqmcL/1GVeH859zU4hLJ8/MLfagz2R2G2hjwXTO6ASmC Tbn/EifM5GU5s00ogR/4pDkaEJV0mx0Kuc3ke5YQ3ejOwv86jURkfdA10pRYixCXk9 eHN0iPOLeIRxB6YuT7kChlJJXqczOUA7TpbGnv6x9+0PnJ8OIkpVBfdzAKubptLFux f5vlO8VPJyRdVR7nHYxhBy5P9mLz6MDZ7hsaV7IkR5nBk/aCTFnXTB2EvkNTeCHqTj XylT6vVd2R/wQ== Received: from [127.0.1.1] (unknown [IPv6:2600:4041:5b1a:9400:62f0:406e:ac79:4a96]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nfraprado) by bali.collaboradmins.com (Postfix) with ESMTPSA id 4B04D17E37C2; Fri, 22 Aug 2025 20:36:56 +0200 (CEST) From: =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Date: Fri, 22 Aug 2025 14:36:14 -0400 Subject: [PATCH RFC 4/5] drm/mediatek: ccorr: Support post-blend color pipeline API Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-mtk-post-blend-color-pipeline-v1-4-a9446d4aca82@collabora.com> References: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> In-Reply-To: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Chun-Kuang Hu , Philipp Zabel , Matthias Brugger , AngeloGioacchino Del Regno Cc: Alex Hung , wayland-devel@lists.freedesktop.org, harry.wentland@amd.com, leo.liu@amd.com, ville.syrjala@linux.intel.com, pekka.paalanen@collabora.com, contact@emersion.fr, mwen@igalia.com, jadahl@redhat.com, sebastian.wick@redhat.com, shashank.sharma@amd.com, agoins@nvidia.com, joshua@froggi.es, mdaenzer@redhat.com, aleixpol@kde.org, xaver.hugl@gmail.com, victoria@system76.com, uma.shankar@intel.com, quic_naseer@quicinc.com, quic_cbraga@quicinc.com, quic_abhinavk@quicinc.com, marcan@marcan.st, Liviu.Dudau@arm.com, sashamcintosh@google.com, chaitanya.kumar.borah@intel.com, louis.chauvet@bootlin.com, mcanal@igalia.com, kernel@collabora.com, daniels@collabora.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= , Simona Vetter X-Mailer: b4 0.14.2 Implement the ctm_set_color_pipeline DDP component function to allow configuring the CTM through the color pipeline API. The color pipeline API only defines a 3x4 matrix, while the driver currently only supports setting the coefficients for a 3x3 matrix. However the underlying hardware does support setting the offset coefficients that make up a 3x4 matrix, so implement support for setting them so the 3x4 matrix structure for the API can be used as is. Also make sure to enable or disable the CTM function depending on whether the block should be bypassed or not. Signed-off-by: N=C3=ADcolas F. R. A. Prado --- drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 3 +- drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 100 ++++++++++++++++++++++++++= ---- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 3 +- 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/medi= atek/mtk_ddp_comp.c index ac6620e10262e3b9a4a82093f13c3101f79520de..c873b527423f51733058cbc3d0a= d2a719e26bfe1 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c @@ -284,7 +284,8 @@ static const struct mtk_ddp_comp_funcs ddp_ccorr =3D { .config =3D mtk_ccorr_config, .start =3D mtk_ccorr_start, .stop =3D mtk_ccorr_stop, - .ctm_set =3D mtk_ccorr_ctm_set, + .ctm_set =3D mtk_ccorr_ctm_set_legacy, + .ctm_set_color_pipeline =3D mtk_ccorr_ctm_set_color_pipeline, }; =20 static const struct mtk_ddp_comp_funcs ddp_color =3D { diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/me= diatek/mtk_disp_ccorr.c index 10d60d2c2a568ebbe09f90e8f42a73e4c2366662..f69a7d8b97f741f0c5461e8cd6f= 38f70b0690e7e 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c @@ -28,6 +28,11 @@ #define DISP_CCORR_COEF_2 0x0088 #define DISP_CCORR_COEF_3 0x008C #define DISP_CCORR_COEF_4 0x0090 +#define DISP_CCORR_OFFSET_0 0x0100 +#define CCORR_OFFSET_EN BIT(31) +#define DISP_CCORR_OFFSET_1 0x0104 +#define DISP_CCORR_OFFSET_2 0x0108 +#define DISP_CCORR_OFFSET_MASK GENMASK(26, 14) =20 struct mtk_disp_ccorr_data { u32 matrix_bits; @@ -101,25 +106,48 @@ static u16 mtk_ctm_s31_32_to_s1_n(u64 in, u32 n) return r; } =20 -void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state) +static void mtk_ccorr_ctm_set(struct device *dev, struct cmdq_pkt *cmdq_pk= t, + void *ctm, bool ctm_3x4) { struct mtk_disp_ccorr *ccorr =3D dev_get_drvdata(dev); - struct drm_property_blob *blob =3D state->ctm; - struct drm_color_ctm *ctm; - const u64 *input; + u64 coeffs_in[9]; + u64 coeffs_offset_in[3]; uint16_t coeffs[9] =3D { 0 }; + uint16_t coeffs_offset[3]; int i; - struct cmdq_pkt *cmdq_pkt =3D NULL; u32 matrix_bits =3D ccorr->data->matrix_bits; + u32 val; + + if (ctm_3x4) { + struct drm_color_ctm_3x4 *ctm_3x4 =3D (struct drm_color_ctm_3x4 *)ctm; + + coeffs_in[0] =3D ctm_3x4->matrix[0]; + coeffs_in[1] =3D ctm_3x4->matrix[1]; + coeffs_in[2] =3D ctm_3x4->matrix[2]; + coeffs_in[3] =3D ctm_3x4->matrix[4]; + coeffs_in[4] =3D ctm_3x4->matrix[5]; + coeffs_in[5] =3D ctm_3x4->matrix[6]; + coeffs_in[6] =3D ctm_3x4->matrix[8]; + coeffs_in[7] =3D ctm_3x4->matrix[9]; + coeffs_in[8] =3D ctm_3x4->matrix[10]; + + coeffs_offset_in[0] =3D ctm_3x4->matrix[3]; + coeffs_offset_in[1] =3D ctm_3x4->matrix[7]; + coeffs_offset_in[2] =3D ctm_3x4->matrix[11]; + } else { + struct drm_color_ctm *ctm_3x3 =3D (struct drm_color_ctm *)ctm; =20 - if (!blob) - return; - - ctm =3D (struct drm_color_ctm *)blob->data; - input =3D ctm->matrix; + for (i =3D 0; i < ARRAY_SIZE(coeffs_in); i++) + coeffs_in[i] =3D ctm_3x3->matrix[i]; + } =20 for (i =3D 0; i < ARRAY_SIZE(coeffs); i++) - coeffs[i] =3D mtk_ctm_s31_32_to_s1_n(input[i], matrix_bits); + coeffs[i] =3D mtk_ctm_s31_32_to_s1_n(coeffs_in[i], matrix_bits); + + if (ctm_3x4) { + for (i =3D 0; i < ARRAY_SIZE(coeffs_offset); i++) + coeffs_offset[i] =3D mtk_ctm_s31_32_to_s1_n(coeffs_offset_in[i], matrix= _bits); + } =20 mtk_ddp_write(cmdq_pkt, coeffs[0] << 16 | coeffs[1], &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_0); @@ -131,6 +159,56 @@ void mtk_ccorr_ctm_set(struct device *dev, struct drm_= crtc_state *state) &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_3); mtk_ddp_write(cmdq_pkt, coeffs[8] << 16, &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_4); + + if (ctm_3x4) { + val =3D CCORR_OFFSET_EN; + val |=3D FIELD_PREP(DISP_CCORR_OFFSET_MASK, coeffs_offset[0]); + mtk_ddp_write(cmdq_pkt, val, &ccorr->cmdq_reg, + ccorr->regs, DISP_CCORR_OFFSET_0); + val =3D FIELD_PREP(DISP_CCORR_OFFSET_MASK, coeffs_offset[1]); + mtk_ddp_write(cmdq_pkt, val, &ccorr->cmdq_reg, + ccorr->regs, DISP_CCORR_OFFSET_1); + val =3D FIELD_PREP(DISP_CCORR_OFFSET_MASK, coeffs_offset[2]); + mtk_ddp_write(cmdq_pkt, val, &ccorr->cmdq_reg, + ccorr->regs, DISP_CCORR_OFFSET_2); + } else { + mtk_ddp_write_mask(cmdq_pkt, 0, &ccorr->cmdq_reg, + ccorr->regs, DISP_CCORR_OFFSET_0, + CCORR_OFFSET_EN); + } + + mtk_ddp_write(cmdq_pkt, CCORR_ENGINE_EN, &ccorr->cmdq_reg, + ccorr->regs, DISP_CCORR_CFG); +} + +void mtk_ccorr_ctm_set_legacy(struct device *dev, struct drm_crtc_state *s= tate) +{ + struct drm_property_blob *blob =3D state->ctm; + struct cmdq_pkt *cmdq_pkt =3D NULL; + struct drm_color_ctm *ctm; + + if (!blob) + return; + + ctm =3D (struct drm_color_ctm *)blob->data; + + mtk_ccorr_ctm_set(dev, cmdq_pkt, ctm, false); +} + +void mtk_ccorr_ctm_set_color_pipeline(struct device *dev, struct drm_color= _ctm_3x4 *ctm) +{ + struct mtk_disp_ccorr *ccorr =3D dev_get_drvdata(dev); + struct cmdq_pkt *cmdq_pkt =3D NULL; + + /* Configure block to be bypassed */ + if (!ctm) { + mtk_ddp_write_mask(cmdq_pkt, CCORR_RELAY_MODE, &ccorr->cmdq_reg, + ccorr->regs, DISP_CCORR_CFG, + CCORR_RELAY_MODE | CCORR_ENGINE_EN); + return; + } + + mtk_ccorr_ctm_set(dev, cmdq_pkt, ctm, true); } =20 static int mtk_disp_ccorr_bind(struct device *dev, struct device *master, diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/medi= atek/mtk_disp_drv.h index 679d413bf10be1e2fc4804a60a3fbe5d734614f6..ac84cf579150fd0535c79f43ad5= 942f8d412d450 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -22,7 +22,8 @@ void mtk_aal_gamma_set(struct device *dev, struct drm_crt= c_state *state); void mtk_aal_start(struct device *dev); void mtk_aal_stop(struct device *dev); =20 -void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state); +void mtk_ccorr_ctm_set_legacy(struct device *dev, struct drm_crtc_state *s= tate); +void mtk_ccorr_ctm_set_color_pipeline(struct device *dev, struct drm_color= _ctm_3x4 *ctm); int mtk_ccorr_clk_enable(struct device *dev); void mtk_ccorr_clk_disable(struct device *dev); void mtk_ccorr_config(struct device *dev, unsigned int w, --=20 2.47.2 From nobody Fri Oct 3 23:02:08 2025 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 960172BEFEF for ; Fri, 22 Aug 2025 18:37:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887831; cv=none; b=dRZEkxkwLqqhUc2mXTdqWMyMHm2NQHYzaBo3GKpveQefygoYaoO8lDRPJadSDUgaEkEmMI0yvDQUq53IK4lBIZT5Y4w+dw9sMssJLhW0DuhbGIJNBduPA/SYRnGhI//mKR7Qqsys7bw2v7C84NGbAhAFXq45/xJcRDZG3sO/9q0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755887831; c=relaxed/simple; bh=WoYBS+suj62us0oVK02xkfT8Ry303QosUdXUG5V5o+s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DzS1LLuaISMG1LfKkOlHWA5zXFGpM7XswFvtRLLO4esk2kfDhnCe0yX817E0bV1Q38DhukEtRysPZcQJVbviEshWU1Im/SN/Gkz60WRh2pOVz3FVd4wslghtfJtcunEt41TH5FsUqIDH9LGelW7dQiCvXPJjSmshjCmRyXyvK6c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=Qn+CCUV/; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="Qn+CCUV/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1755887828; bh=WoYBS+suj62us0oVK02xkfT8Ry303QosUdXUG5V5o+s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Qn+CCUV/8f0B211PQEIZ3ASGTBtreAbGZUgjGTj0oNYjtUraf6QXNcC/4t3NsI3o7 v9OEIe2saKYvd9+raIU5ENp1g9NAL9Qx2Ea/6ya9nzp8YooSlv6Ekv0f5IALcLL9Kx sn+cq93AW2B49ksS2SCYWiLBk0sX1GYHqyiExbRHP7E926Ha4R+X6vHgcHwyGAGlzG Mrt5s/RVuUeVI1gT8IA9SjyIOgEbAaw+p0mtSEuQmNh0UyKVbIofc+u3gF5VjaaBSY TdeRPDR991v1g/voBpo3RV70ffswkZsDVr3pf9ICxPkgnZ8a7VPzEsnM3fNZqTNsHm 4GYkF5elPocZw== Received: from [127.0.1.1] (unknown [IPv6:2600:4041:5b1a:9400:62f0:406e:ac79:4a96]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nfraprado) by bali.collaboradmins.com (Postfix) with ESMTPSA id AF06617E37EB; Fri, 22 Aug 2025 20:37:02 +0200 (CEST) From: =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= Date: Fri, 22 Aug 2025 14:36:15 -0400 Subject: [PATCH RFC 5/5] drm/mediatek: gamma: Support post-blend color pipeline API Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-mtk-post-blend-color-pipeline-v1-5-a9446d4aca82@collabora.com> References: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> In-Reply-To: <20250822-mtk-post-blend-color-pipeline-v1-0-a9446d4aca82@collabora.com> To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Chun-Kuang Hu , Philipp Zabel , Matthias Brugger , AngeloGioacchino Del Regno Cc: Alex Hung , wayland-devel@lists.freedesktop.org, harry.wentland@amd.com, leo.liu@amd.com, ville.syrjala@linux.intel.com, pekka.paalanen@collabora.com, contact@emersion.fr, mwen@igalia.com, jadahl@redhat.com, sebastian.wick@redhat.com, shashank.sharma@amd.com, agoins@nvidia.com, joshua@froggi.es, mdaenzer@redhat.com, aleixpol@kde.org, xaver.hugl@gmail.com, victoria@system76.com, uma.shankar@intel.com, quic_naseer@quicinc.com, quic_cbraga@quicinc.com, quic_abhinavk@quicinc.com, marcan@marcan.st, Liviu.Dudau@arm.com, sashamcintosh@google.com, chaitanya.kumar.borah@intel.com, louis.chauvet@bootlin.com, mcanal@igalia.com, kernel@collabora.com, daniels@collabora.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?N=C3=ADcolas_F=2E_R=2E_A=2E_Prado?= , Simona Vetter X-Mailer: b4 0.14.2 Implement the gamma_set_color_pipeline DDP component function to allow configuring the gamma LUT through the post-blend color pipeline API. The color pipeline API uses a 32-bit long, rather than 16-bit long, LUT, so also update the functions to handle both cases. Also make sure to enable or disable the LUT function depending on whether the block should be bypassed or not. Signed-off-by: N=C3=ADcolas F. R. A. Prado --- drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 3 +- drivers/gpu/drm/mediatek/mtk_disp_drv.h | 3 +- drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 107 +++++++++++++++++++++++++-= ---- 3 files changed, 94 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/medi= atek/mtk_ddp_comp.c index c873b527423f51733058cbc3d0ad2a719e26bfe1..d253906546506ecf1f1e2a23123= b80e774e981ae 100644 --- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c @@ -327,7 +327,8 @@ static const struct mtk_ddp_comp_funcs ddp_gamma =3D { .clk_enable =3D mtk_gamma_clk_enable, .clk_disable =3D mtk_gamma_clk_disable, .gamma_get_lut_size =3D mtk_gamma_get_lut_size, - .gamma_set =3D mtk_gamma_set, + .gamma_set =3D mtk_gamma_set_legacy, + .gamma_set_color_pipeline =3D mtk_gamma_set_color_pipeline, .config =3D mtk_gamma_config, .start =3D mtk_gamma_start, .stop =3D mtk_gamma_stop, diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/medi= atek/mtk_disp_drv.h index ac84cf579150fd0535c79f43ad5942f8d412d450..7795aa5bc057fc09597cbd582f0= 4e4dc76d3ecba 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -58,7 +58,8 @@ void mtk_gamma_config(struct device *dev, unsigned int w, unsigned int h, unsigned int vrefresh, unsigned int bpc, struct cmdq_pkt *cmdq_pkt); unsigned int mtk_gamma_get_lut_size(struct device *dev); -void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state); +void mtk_gamma_set_legacy(struct device *dev, struct drm_crtc_state *state= ); +void mtk_gamma_set_color_pipeline(struct device *dev, struct drm_color_lut= 32 *lut); void mtk_gamma_start(struct device *dev); void mtk_gamma_stop(struct device *dev); =20 diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/me= diatek/mtk_disp_gamma.c index 8afd15006df2a21f3f52fe00eca3c5501f4fb76a..dec9eeb53cb8539e49ecc1087e0= 37645c792ee3d 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c @@ -87,13 +87,34 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev) return 0; } =20 -static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 lut= _size) +static bool mtk_gamma_lut_is_descending(void *lut, bool bits32, u32 lut_si= ze) { u64 first, last; int last_entry =3D lut_size - 1; + u32 lutr_first, lutg_first, lutb_first, lutr_last, lutg_last, lutb_last; + struct drm_color_lut32 *lut32; + struct drm_color_lut *lut16; + + if (bits32) { + lut32 =3D (struct drm_color_lut32 *)lut; + lutr_first =3D lut32[0].red; + lutg_first =3D lut32[0].green; + lutb_first =3D lut32[0].blue; + lutr_last =3D lut32[last_entry].red; + lutg_last =3D lut32[last_entry].green; + lutb_last =3D lut32[last_entry].blue; + } else { + lut16 =3D (struct drm_color_lut *)lut; + lutr_first =3D lut16[0].red; + lutg_first =3D lut16[0].green; + lutb_first =3D lut16[0].blue; + lutr_last =3D lut16[last_entry].red; + lutg_last =3D lut16[last_entry].green; + lutb_last =3D lut16[last_entry].blue; + } =20 - first =3D lut[0].red + lut[0].green + lut[0].blue; - last =3D lut[last_entry].red + lut[last_entry].green + lut[last_entry].bl= ue; + first =3D lutr_first + lutg_first + lutb_first; + last =3D lutr_last + lutg_last + lutb_last; =20 return !!(first > last); } @@ -113,7 +134,7 @@ static bool mtk_gamma_lut_is_descending(struct drm_colo= r_lut *lut, u32 lut_size) * - 12-bits LUT supported * - 10-its LUT not supported */ -void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state) +static void mtk_gamma_set(struct device *dev, void *lut, bool bits32) { struct mtk_disp_gamma *gamma =3D dev_get_drvdata(dev); void __iomem *lut0_base =3D gamma->regs + DISP_GAMMA_LUT; @@ -121,19 +142,20 @@ void mtk_gamma_set(struct device *dev, struct drm_crt= c_state *state) u32 cfg_val, data_mode, lbank_val, word[2]; u8 lut_bits =3D gamma->data->lut_bits; int cur_bank, num_lut_banks; - struct drm_color_lut *lut; unsigned int i; - - /* If there's no gamma lut there's nothing to do here. */ - if (!state->gamma_lut) - return; + struct drm_color_lut32 *lut32; + struct drm_color_lut *lut16; =20 num_lut_banks =3D gamma->data->lut_size / gamma->data->lut_bank_size; - lut =3D (struct drm_color_lut *)state->gamma_lut->data; =20 /* Switch to 12 bits data mode if supported */ data_mode =3D FIELD_PREP(DISP_GAMMA_BANK_DATA_MODE, !!(lut_bits =3D=3D 12= )); =20 + if (bits32) + lut32 =3D (struct drm_color_lut32 *)lut; + else + lut16 =3D (struct drm_color_lut *)lut; + for (cur_bank =3D 0; cur_bank < num_lut_banks; cur_bank++) { =20 /* Switch gamma bank and set data mode before writing LUT */ @@ -146,10 +168,21 @@ void mtk_gamma_set(struct device *dev, struct drm_crt= c_state *state) for (i =3D 0; i < gamma->data->lut_bank_size; i++) { int n =3D cur_bank * gamma->data->lut_bank_size + i; struct drm_color_lut diff, hwlut; + u32 lutr, lutg, lutb; + + if (bits32) { + lutr =3D lut32[n].red; + lutg =3D lut32[n].green; + lutb =3D lut32[n].blue; + } else { + lutr =3D lut16[n].red; + lutg =3D lut16[n].green; + lutb =3D lut16[n].blue; + } =20 - hwlut.red =3D drm_color_lut_extract(lut[n].red, lut_bits); - hwlut.green =3D drm_color_lut_extract(lut[n].green, lut_bits); - hwlut.blue =3D drm_color_lut_extract(lut[n].blue, lut_bits); + hwlut.red =3D drm_color_lut_extract(lutr, lut_bits); + hwlut.green =3D drm_color_lut_extract(lutg, lut_bits); + hwlut.blue =3D drm_color_lut_extract(lutb, lut_bits); =20 if (!gamma->data->lut_diff || (i % 2 =3D=3D 0)) { if (lut_bits =3D=3D 12) { @@ -162,13 +195,25 @@ void mtk_gamma_set(struct device *dev, struct drm_crt= c_state *state) word[0] |=3D FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue); } } else { - diff.red =3D lut[n].red - lut[n - 1].red; + u32 lutr_prev, lutg_prev, lutb_prev; + + if (bits32) { + lutr_prev =3D lut32[n-1].red; + lutg_prev =3D lut32[n-1].green; + lutb_prev =3D lut32[n-1].blue; + } else { + lutr_prev =3D lut16[n-1].red; + lutg_prev =3D lut16[n-1].green; + lutb_prev =3D lut16[n-1].blue; + } + + diff.red =3D lutr - lutr_prev; diff.red =3D drm_color_lut_extract(diff.red, lut_bits); =20 - diff.green =3D lut[n].green - lut[n - 1].green; + diff.green =3D lutg - lutg_prev; diff.green =3D drm_color_lut_extract(diff.green, lut_bits); =20 - diff.blue =3D lut[n].blue - lut[n - 1].blue; + diff.blue =3D lutb - lutb_prev; diff.blue =3D drm_color_lut_extract(diff.blue, lut_bits); =20 if (lut_bits =3D=3D 12) { @@ -191,7 +236,7 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_= state *state) =20 if (!gamma->data->has_dither) { /* Descending or Rising LUT */ - if (mtk_gamma_lut_is_descending(lut, gamma->data->lut_size - 1)) + if (mtk_gamma_lut_is_descending(lut, bits32, gamma->data->lut_size - 1)) cfg_val |=3D FIELD_PREP(GAMMA_LUT_TYPE, 1); else cfg_val &=3D ~GAMMA_LUT_TYPE; @@ -206,6 +251,34 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc= _state *state) writel(cfg_val, gamma->regs + DISP_GAMMA_CFG); } =20 +void mtk_gamma_set_legacy(struct device *dev, struct drm_crtc_state *state) +{ + struct drm_color_lut *lut =3D (struct drm_color_lut *)state->gamma_lut->d= ata; + + /* If there's no gamma lut there's nothing to do here. */ + if (!state->gamma_lut) + return; + + mtk_gamma_set(dev, lut, false); +} + +void mtk_gamma_set_color_pipeline(struct device *dev, struct drm_color_lut= 32 *lut) +{ + struct mtk_disp_gamma *gamma =3D dev_get_drvdata(dev); + u32 cfg_val; + + /* Configure block to be bypassed */ + if (!lut) { + cfg_val =3D readl(gamma->regs + DISP_GAMMA_CFG); + cfg_val &=3D ~GAMMA_LUT_EN; + cfg_val |=3D GAMMA_RELAY_MODE; + writel(cfg_val, gamma->regs + DISP_GAMMA_CFG); + return; + } + + mtk_gamma_set(dev, lut, true); +} + void mtk_gamma_config(struct device *dev, unsigned int w, unsigned int h, unsigned int vrefresh, unsigned int bpc, struct cmdq_pkt *cmdq_pkt) --=20 2.47.2