On Tue Jun 30 09:41:28 2026 +0200, Jacopo Mondi wrote:
> Add support for Gamma curve correction for the Mali C55 ISP.
> 
> Define a new block in the uAPI using the extensible v4l2-isp format and
> implement support for configuring the RGB Gamma parameters in the
> mali-c55 parameters handler.
> 
> While at it, rename the MALI_C55_REG_GAMMA_GAINS_[1|2] register name
> to MALI_C55_REG_GAMMA_GAINS_[RG|B] and the
> MALI_C55_REG_GAMMA_OFFSETS_[1|2] register name to
> MALI_C55_REG_GAMMA_OFFSETS_[RG|B] to better clarify their intent.
> 
> Signed-off-by: Jacopo Mondi <[email protected]>
> Reviewed-by: Vincenzo Frascino <[email protected]>
> Reviewed-by: Linus Walleij <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 .../media/platform/arm/mali-c55/mali-c55-params.c  | 75 ++++++++++++++++++++++
 .../platform/arm/mali-c55/mali-c55-registers.h     | 13 ++--
 include/uapi/linux/media/arm/mali-c55-config.h     | 47 +++++++++++++-
 3 files changed, 130 insertions(+), 5 deletions(-)

---

diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-params.c 
b/drivers/media/platform/arm/mali-c55/mali-c55-params.c
index 98f780cd46fe..e53c7b512dbd 100644
--- a/drivers/media/platform/arm/mali-c55/mali-c55-params.c
+++ b/drivers/media/platform/arm/mali-c55/mali-c55-params.c
@@ -47,6 +47,8 @@
  * @shading_config:    For header->type == MALI_C55_PARAM_MESH_SHADING_CONFIG
  * @shading_selection: For header->type == 
MALI_C55_PARAM_MESH_SHADING_SELECTION
  * @ccm:               For header->type == MALI_C55_PARAM_BLOCK_CCM
+ * @gamma:             For header->type == MALI_C55_PARAM_BLOCK_GAMMA_FR and
+ *                     header->type = MALI_C55_PARAM_BLOCK_GAMMA_DS
  * @data:              Allows easy initialisation of a union variable with a
  *                     pointer into a __u8 array.
  */
@@ -61,6 +63,7 @@ union mali_c55_params_block {
        const struct mali_c55_params_mesh_shading_config *shading_config;
        const struct mali_c55_params_mesh_shading_selection *shading_selection;
        const struct mali_c55_params_ccm *ccm;
+       const struct mali_c55_params_gamma *gamma;
        const __u8 *data;
 };
 
@@ -463,6 +466,70 @@ static void mali_c55_params_ccm(struct mali_c55 *mali_c55,
        mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 1);
 }
 
+static void mali_c55_params_gamma(struct mali_c55 *mali_c55,
+                                 union mali_c55_params_block block,
+                                 __u32 offset, __u32 lut_base)
+{
+       const struct mali_c55_params_gamma *params = block.gamma;
+
+       if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) {
+               mali_c55_ctx_update_bits(mali_c55,
+                                        MALI_C55_REG_GAMMA_RGB_ENABLE + offset,
+                                        MALI_C55_GAMMA_ENABLE_MASK, 0x00);
+               return;
+       }
+
+       mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_RG + offset,
+                                MALI_C55_GAMMA_GAIN_R_MASK, params->gains[0]);
+       mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_RG + offset,
+                                MALI_C55_GAMMA_GAIN_G_MASK,
+                                MALI_C55_GAMMA_GAIN_G(params->gains[1]));
+       mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_B + offset,
+                                MALI_C55_GAMMA_GAIN_B_MASK, params->gains[2]);
+       mali_c55_ctx_update_bits(mali_c55,
+                                MALI_C55_REG_GAMMA_OFFSETS_RG + offset,
+                                MALI_C55_GAMMA_OFFSET_R_MASK,
+                                params->offs[0]);
+       mali_c55_ctx_update_bits(mali_c55,
+                                MALI_C55_REG_GAMMA_OFFSETS_RG + offset,
+                                MALI_C55_GAMMA_OFFSET_G_MASK,
+                                MALI_C55_GAMMA_OFFSET_G(params->offs[1]));
+       mali_c55_ctx_update_bits(mali_c55,
+                                MALI_C55_REG_GAMMA_OFFSETS_B + offset,
+                                MALI_C55_GAMMA_OFFSET_B_MASK,
+                                params->offs[2]);
+
+       for (unsigned int i = 0; i < MALI_C55_NUM_GAMMA_LUT_ELEMENTS; i++) {
+               __u32 addr = lut_base + (i * 4);
+
+               mali_c55_ctx_write(mali_c55, addr, params->lut[i]);
+       }
+
+       mali_c55_ctx_update_bits(mali_c55,
+                                MALI_C55_REG_GAMMA_RGB_ENABLE + offset,
+                                MALI_C55_GAMMA_ENABLE_MASK, 0x1);
+}
+
+static void mali_c55_params_gamma_fr(struct mali_c55 *mali_c55,
+                                    union mali_c55_params_block block)
+{
+       return mali_c55_params_gamma(mali_c55, block,
+                                    MALI_C55_CAP_DEV_FR_REG_OFFSET,
+                                    MALI_C55_REG_FR_GAMMA_RGB_MEM);
+}
+
+static void mali_c55_params_gamma_ds(struct mali_c55 *mali_c55,
+                                    union mali_c55_params_block block)
+{
+       /* We cannot apply parameters to DS if it is not fitted. */
+       if (!(mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED))
+               return;
+
+       return mali_c55_params_gamma(mali_c55, block,
+                                    MALI_C55_CAP_DEV_DS_REG_OFFSET,
+                                    MALI_C55_REG_DS_GAMMA_RGB_MEM);
+}
+
 static const mali_c55_params_handler mali_c55_params_handlers[] = {
        [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = &mali_c55_params_sensor_offs,
        [MALI_C55_PARAM_BLOCK_AEXP_HIST] = &mali_c55_params_aexp_hist,
@@ -476,6 +543,8 @@ static const mali_c55_params_handler 
mali_c55_params_handlers[] = {
        [MALI_C55_PARAM_MESH_SHADING_CONFIG] = &mali_c55_params_lsc_config,
        [MALI_C55_PARAM_MESH_SHADING_SELECTION] = 
&mali_c55_params_lsc_selection,
        [MALI_C55_PARAM_BLOCK_CCM] = &mali_c55_params_ccm,
+       [MALI_C55_PARAM_BLOCK_GAMMA_FR] = &mali_c55_params_gamma_fr,
+       [MALI_C55_PARAM_BLOCK_GAMMA_DS] = &mali_c55_params_gamma_ds,
 };
 
 static const struct v4l2_isp_params_block_type_info
@@ -516,6 +585,12 @@ mali_c55_params_block_types_info[] = {
        [MALI_C55_PARAM_BLOCK_CCM] = {
                .size = sizeof(struct mali_c55_params_ccm),
        },
+       [MALI_C55_PARAM_BLOCK_GAMMA_FR] = {
+               .size = sizeof(struct mali_c55_params_gamma),
+       },
+       [MALI_C55_PARAM_BLOCK_GAMMA_DS] = {
+               .size = sizeof(struct mali_c55_params_gamma),
+       },
 };
 
 static_assert(ARRAY_SIZE(mali_c55_params_handlers) ==
diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h 
b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h
index 4cd13b702d9f..8a7c3bfe7051 100644
--- a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h
+++ b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h
@@ -422,15 +422,17 @@ enum mali_c55_interrupts {
 
 #define MALI_C55_REG_GAMMA_RGB_ENABLE                  0x1c064
 #define MALI_C55_GAMMA_ENABLE_MASK                     BIT(0)
-#define MALI_C55_REG_GAMMA_GAINS_1                     0x1c068
+#define MALI_C55_REG_GAMMA_GAINS_RG                    0x1c068
 #define MALI_C55_GAMMA_GAIN_R_MASK                     GENMASK(11, 0)
 #define MALI_C55_GAMMA_GAIN_G_MASK                     GENMASK(27, 16)
-#define MALI_C55_REG_GAMMA_GAINS_2                     0x1c06c
+#define MALI_C55_GAMMA_GAIN_G(x)                       ((x) << 16)
+#define MALI_C55_REG_GAMMA_GAINS_B                     0x1c06c
 #define MALI_C55_GAMMA_GAIN_B_MASK                     GENMASK(11, 0)
-#define MALI_C55_REG_GAMMA_OFFSETS_1                   0x1c070
+#define MALI_C55_REG_GAMMA_OFFSETS_RG                  0x1c070
 #define MALI_C55_GAMMA_OFFSET_R_MASK                   GENMASK(11, 0)
 #define MALI_C55_GAMMA_OFFSET_G_MASK                   GENMASK(27, 16)
-#define MALI_C55_REG_GAMMA_OFFSETS_2                   0x1c074
+#define MALI_C55_GAMMA_OFFSET_G(x)                     ((x) << 16)
+#define MALI_C55_REG_GAMMA_OFFSETS_B                   0x1c074
 #define MALI_C55_GAMMA_OFFSET_B_MASK                   GENMASK(11, 0)
 
 /*
@@ -441,6 +443,9 @@ enum mali_c55_interrupts {
 #define MALI_C55_REG_FR_GAMMA_RGB_ENABLE               0x1c064
 #define MALI_C55_REG_DS_GAMMA_RGB_ENABLE               0x1c1d8
 
+#define MALI_C55_REG_FR_GAMMA_RGB_MEM                  0x18280
+#define MALI_C55_REG_DS_GAMMA_RGB_MEM                  0x18484
+
 #define MALI_C55_REG_FR_SCALER_HFILT                   0x34a8
 #define MALI_C55_REG_FR_SCALER_VFILT                   0x44a8
 #define MALI_C55_REG_DS_SCALER_HFILT                   0x14a8
diff --git a/include/uapi/linux/media/arm/mali-c55-config.h 
b/include/uapi/linux/media/arm/mali-c55-config.h
index 0b18863f973d..ef0fe17df96e 100644
--- a/include/uapi/linux/media/arm/mali-c55-config.h
+++ b/include/uapi/linux/media/arm/mali-c55-config.h
@@ -36,6 +36,9 @@
  */
 #define MALI_C55_MAX_ZONES     (15 * 15)
 
+/* Number of RGB gamma LUT entries. */
+#define MALI_C55_NUM_GAMMA_LUT_ELEMENTS 129
+
 /**
  * struct mali_c55_ae_1024bin_hist - Auto Exposure 1024-bin histogram 
statistics
  *
@@ -220,6 +223,8 @@ struct mali_c55_stats_buffer {
  * @MALI_C55_PARAM_MESH_SHADING_CONFIG : Mesh shading tables configuration
  * @MALI_C55_PARAM_MESH_SHADING_SELECTION: Mesh shading table selection
  * @MALI_C55_PARAM_BLOCK_CCM: Colour correction matrix
+ * @MALI_C55_PARAM_BLOCK_GAMMA_FR: Gamma gain and offset for FR pipe
+ * @MALI_C55_PARAM_BLOCK_GAMMA_DS: Gamma gain and offset for DS pipe
  */
 enum mali_c55_param_block_type {
        MALI_C55_PARAM_BLOCK_SENSOR_OFFS,
@@ -234,6 +239,8 @@ enum mali_c55_param_block_type {
        MALI_C55_PARAM_MESH_SHADING_CONFIG,
        MALI_C55_PARAM_MESH_SHADING_SELECTION,
        MALI_C55_PARAM_BLOCK_CCM,
+       MALI_C55_PARAM_BLOCK_GAMMA_FR,
+       MALI_C55_PARAM_BLOCK_GAMMA_DS,
 };
 
 /**
@@ -795,6 +802,42 @@ struct mali_c55_params_ccm {
        __u16 offs[3];
 };
 
+/**
+ * struct mali_c55_params_gamma - RGB Gamma correction
+ *
+ * Gamma correction is used to program a standard gamma curve such as the sRGB
+ * one. It provides gains and offsets to implement contrast adjustments.
+ *
+ * Gamma correction is applied on both the FR and DS pipes separately in the 
RGB
+ * colour domain where the following operations take place:
+ * 1) An offset is subtracted from each colour channel
+ * 2) Each colour channel is multiplied by a gain
+ * 3) The Gamma LUT is applied to each colour channel
+ *
+ * The Gamma LUT has 129 entries where each node is an unsigned 12 bit number.
+ * It is expected that LUT[0]=0 and LUT[128]=0xfff, with the other 127 values
+ * defining the Gamma correction curve. The three gain multipliers are 
expressed
+ * as 12-bits unsigned Q4.8 fixed-point numbers and the three offsets are
+ * expressed as a 12-bits unsigned integers.
+ *
+ * As one Gamma correction block is available on both the FR and DS pipes, the
+ * header.type field should be set to one of either
+ * MALI_C55_PARAM_BLOCK_GAMMA_FR or MALI_C55_PARAM_BLOCK_GAMMA_DS from
+ * :c:type:`mali_c55_param_block_type`.
+ *
+ * @header:    The Mali-C55 parameters block header
+ * @gains:     Gains for the red, green and blue channel in unsigned Q4.8 
format
+ * @offs:      Offsets subtracted from the red, green and blue channels
+ *             in unsigned 12 bits format
+ * @lut:       129-node Gamma LUT in unsigned 12 bits format
+ */
+struct mali_c55_params_gamma {
+       struct v4l2_isp_params_block_header header;
+       __u16 gains[3];
+       __u16 offs[3];
+       __u32 lut[MALI_C55_NUM_GAMMA_LUT_ELEMENTS];
+};
+
 /**
  * define MALI_C55_PARAMS_MAX_SIZE - Maximum size of all Mali C55 Parameters
  *
@@ -819,6 +862,8 @@ struct mali_c55_params_ccm {
        sizeof(struct mali_c55_params_awb_gains) +              \
        sizeof(struct mali_c55_params_mesh_shading_config) +    \
        sizeof(struct mali_c55_params_mesh_shading_selection) + \
-       sizeof(struct mali_c55_params_ccm))
+       sizeof(struct mali_c55_params_ccm) +                    \
+       sizeof(struct mali_c55_params_gamma) +                  \
+       sizeof(struct mali_c55_params_gamma))
 
 #endif /* __UAPI_MALI_C55_CONFIG_H */
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to