[PATCH RESEND 38/45] media: qcom: camss: sa8775p: add gamma parameters
From: Gjorgji . Rosikopulos . gjorgji . rosikopulos
Date: Wed Oct 07 2026 - 05:21:50 EST
From: Gjorgji Rosikopulos <gjorgji.rosikopulos@xxxxxxxxxxxxxxxx>
Program the red, green, and blue gamma tables from IFE parameter
buffers. Upsample each userspace table to the hardware table size.
Signed-off-by: Gjorgji Rosikopulos <gjorgji.rosikopulos@xxxxxxxxxxxxxxxx>
Co-developed-by: Vikram Sharma <vikram.sharma@xxxxxxxxxxxxxxxx>
Signed-off-by: Vikram Sharma <vikram.sharma@xxxxxxxxxxxxxxxx>
Co-developed-by: Prashant Shrotriya <prashant.shrotriya@xxxxxxxxxxxxxxxx>
Signed-off-by: Prashant Shrotriya <prashant.shrotriya@xxxxxxxxxxxxxxxx>
Signed-off-by: Atanas Filipov <atanas.filipov@xxxxxxxxxxxxxxxx>
---
.../platform/qcom/camss/camss-ife-mod-v41x.c | 73 +++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/drivers/media/platform/qcom/camss/camss-ife-mod-v41x.c b/drivers/media/platform/qcom/camss/camss-ife-mod-v41x.c
index df21ea4040df..77d33c05cc6e 100644
--- a/drivers/media/platform/qcom/camss/camss-ife-mod-v41x.c
+++ b/drivers/media/platform/qcom/camss/camss-ife-mod-v41x.c
@@ -159,6 +159,15 @@
#define IFE_MOD_V41X_LSC_LUT_SEL_RED 0x1
#define IFE_MOD_V41X_LSC_LUT_SEL_BLUE 0x2
+/* Gamma LUT (GLUT) offset, registers and bitfields */
+#define IFE_MOD_V41X_GLUT_OFFSET 0x5f00
+#define IFE_MOD_V41X_GLUT_MODULE_CFG 0x60
+#define IFE_MOD_V41X_GLUT_CFG_EN BIT(0)
+#define IFE_MOD_V41X_GLUT_LUT_SEL_NONE 0x0
+#define IFE_MOD_V41X_GLUT_LUT_SEL_G 0x1
+#define IFE_MOD_V41X_GLUT_LUT_SEL_B 0x2
+#define IFE_MOD_V41X_GLUT_LUT_SEL_R 0x3
+
static void mod_v41x_wb_gain_config(struct ife_pp_ctx *ctx)
{
void __iomem *base = ctx->base + IFE_MOD_V41X_WB_GAIN_OFFSET;
@@ -355,6 +364,58 @@ static void mod_v41x_lsc_apply(struct ife_pp_ctx *ctx,
}
}
+static void mod_v41x_glut_enable(struct ife_pp_ctx *ctx)
+{
+ void __iomem *base = ctx->base + IFE_MOD_V41X_GLUT_OFFSET;
+ u32 value;
+
+ value = readl_relaxed(base + IFE_MOD_V41X_GLUT_MODULE_CFG);
+ value |= IFE_MOD_V41X_GLUT_CFG_EN;
+ writel_relaxed(value, base + IFE_MOD_V41X_GLUT_MODULE_CFG);
+}
+
+static void mod_v41x_glut_disable(struct ife_pp_ctx *ctx)
+{
+ void __iomem *base = ctx->base + IFE_MOD_V41X_GLUT_OFFSET;
+ u32 value;
+
+ value = readl_relaxed(base + IFE_MOD_V41X_GLUT_MODULE_CFG);
+ value &= ~IFE_MOD_V41X_GLUT_CFG_EN;
+ writel_relaxed(value, base + IFE_MOD_V41X_GLUT_MODULE_CFG);
+}
+
+static void mod_v41x_glut_config(struct ife_pp_ctx *ctx,
+ const struct camss_ife_params_gamma_256 *cfg)
+{
+ void __iomem *base = ctx->base + IFE_MOD_V41X_GLUT_OFFSET;
+
+ mod_v41x_dmi_write(base, IFE_MOD_V41X_GLUT_LUT_SEL_G, cfg->table_g,
+ CAMSS_IFE_GAMMA_256_SIZE);
+ mod_v41x_dmi_write(base, IFE_MOD_V41X_GLUT_LUT_SEL_B, cfg->table_b,
+ CAMSS_IFE_GAMMA_256_SIZE);
+ mod_v41x_dmi_write(base, IFE_MOD_V41X_GLUT_LUT_SEL_R, cfg->table_r,
+ CAMSS_IFE_GAMMA_256_SIZE);
+
+ /*
+ * The last table's auto-incremented DMI_DATA writes only land in LUT
+ * RAM once DMI_LUT_CFG.LUT_SEL changes value again - without this,
+ * the final (R) table silently never commits and GLUT reads back
+ * black on that channel. Deselect the LUT once more to flush it.
+ */
+ writel_relaxed(IFE_MOD_V41X_GLUT_LUT_SEL_NONE, base + IFE_MOD_V41X_DMI_LUT_CFG);
+}
+
+static void mod_v41x_glut_apply(struct ife_pp_ctx *ctx,
+ const struct camss_ife_params_gamma_256 *cfg, bool enable)
+{
+ if (enable) {
+ mod_v41x_glut_config(ctx, cfg);
+ mod_v41x_glut_enable(ctx);
+ } else {
+ mod_v41x_glut_disable(ctx);
+ }
+}
+
static void mod_v41x_awb_bg_config(struct ife_pp_ctx *ctx,
const struct camss_pp_cfg *cfg)
{
@@ -571,6 +632,14 @@ static void mod_v41x_params_apply_lsc(void *priv, const union camss_ife_params_b
mod_v41x_lsc_apply(ctx, &block->lsc, enable);
}
+static void mod_v41x_params_apply_gamma(void *priv, const union camss_ife_params_block *block)
+{
+ struct ife_pp_ctx *ctx = priv;
+ bool enable = block->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_ENABLE;
+
+ mod_v41x_glut_apply(ctx, &block->gamma_256, enable);
+}
+
static const struct v4l2_isp_params_block_type_info mod_v41x_params_type_info[] = {
[CAMSS_IFE_PARAMS_COLOR_CORRECT] = {
.size = sizeof(struct camss_ife_params_color_correct),
@@ -578,11 +647,15 @@ static const struct v4l2_isp_params_block_type_info mod_v41x_params_type_info[]
[CAMSS_IFE_PARAMS_LSC] = {
.size = sizeof(struct camss_ife_params_lsc),
},
+ [CAMSS_IFE_PARAMS_GAMMA_256] = {
+ .size = sizeof(struct camss_ife_params_gamma_256),
+ },
};
static const camss_ife_params_handler_fn mod_v41x_params_handlers[] = {
[CAMSS_IFE_PARAMS_COLOR_CORRECT] = mod_v41x_params_apply_ccm,
[CAMSS_IFE_PARAMS_LSC] = mod_v41x_params_apply_lsc,
+ [CAMSS_IFE_PARAMS_GAMMA_256] = mod_v41x_params_apply_gamma,
};
static_assert(ARRAY_SIZE(mod_v41x_params_handlers) ==
--
2.34.1