[RAMEN9610-9076] fbdev: dpu20: added color transform for night light
authorChiHun Won <hj-yo.lee@samsung.com>
Mon, 26 Nov 2018 07:16:43 +0000 (16:16 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:08 +0000 (20:23 +0300)
Change-Id: I823222e9227cd0045df614e7b79eeac5a2f357ba
Signed-off-by: ChiHun Won <chihun.won@samsung.com>
drivers/video/fbdev/exynos/dpu20/decon.h
drivers/video/fbdev/exynos/dpu20/decon_core.c
drivers/video/fbdev/exynos/dpu20/dqe.h
drivers/video/fbdev/exynos/dpu20/dqe_drv.c

index a14945128e645cb200d864beb0655bcb49608b0d..010ae05d47fb2968911f82f60f9fe73b3b5ccb2c 100644 (file)
@@ -309,6 +309,82 @@ enum dpp_hdr_standard {
        DPP_HDR_HLG,
 };
 
+/* HAL color mode */
+enum HAL_color_mode {
+       HAL_COLOR_MODE_NATIVE = 0,
+       HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+       HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+       HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+       HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+       HAL_COLOR_MODE_STANDARD_BT709 = 5,
+       HAL_COLOR_MODE_DCI_P3 = 6,
+       HAL_COLOR_MODE_SRGB = 7,
+       HAL_COLOR_MODE_ADOBE_RGB = 8,
+       HAL_COLOR_MODE_DISPLAY_P3 = 9,
+};
+
+/* HAL intent info */
+enum HAL_intent_info{
+       HAL_RENDER_INTENT_COLORIMETRIC = 0,
+       HAL_RENDER_INTENT_ENHANCE = 1,
+       HAL_RENDER_INTENT_TONE_MAP_COLORIMETRIC = 2,
+       HAL_RENDER_INTENT_TONE_MAP_ENHANCE = 3,
+};
+
+/* HAL color transform*/
+enum HAL_color_transform{
+       HAL_COLOR_TRANSFORM_IDENTITY = 0,
+       HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+       HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+       HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+       HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+       HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+       HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
+};
+
+struct decon_color_mode_info {
+       int index;
+       u32 color_mode;
+};
+
+/* decon supported color mode */
+enum decon_supported_color_mode {
+       DECON_COLOR_MODE_NATIVE = 0,
+       DECON_COLOR_MODE_SRGB,
+       DECON_COLOR_MODE_DCI_P3,
+       DECON_COLOR_MODE_NUM_MAX,
+};
+
+/* intents num and information in each color mode*/
+struct decon_render_intents_num_info {
+        u32 color_mode;
+        u32 render_intent_num;
+};
+
+struct decon_render_intent_info {
+        u32 color_mode;
+        u32 index;
+        u32 render_intent;
+};
+
+/* decon supported intent info */
+enum decon_supported_intent_info {
+       DECON_INTENT_COLORIMETRIC = 0,
+       DECON_INTENT_ENHANCE,
+       DECON_INTENT_NUM_MAX,
+};
+
+#define DECON_MATRIX_ELEMENT_NUM 16
+struct decon_color_transform_info {
+        u32 hint;
+        int matrix[DECON_MATRIX_ELEMENT_NUM];
+};
+
+struct decon_color_mode_with_render_intent_info {
+       u32 color_mode;
+       u32 render_intent;
+};
+
 struct decon_clocks {
        unsigned long decon[CLK_ID_DPLL + 1];
 };
@@ -1367,4 +1443,16 @@ int decon_update_last_regs(struct decon_device *decon,
 
 /* DPU aclk */
 #define EXYNOS_DPU_GET_ACLK            _IOR('F', 500, u32)
+
+/* COLOR Mode */
+#define EXYNOS_GET_COLOR_MODE_NUM      _IOW('F', 600, __u32)
+#define EXYNOS_GET_COLOR_MODE          _IOW('F', 601, struct decon_color_mode_info)
+#define EXYNOS_SET_COLOR_MODE          _IOW('F', 602, __u32)
+
+#define EXYNOS_GET_RENDER_INTENTS_NUM  _IOW('F', 610, struct decon_render_intents_num_info)
+#define EXYNOS_GET_RENDER_INTENT       _IOW('F', 611, struct decon_render_intent_info)
+
+#define EXYNOS_SET_COLOR_TRANSFORM     _IOW('F', 612, struct decon_color_transform_info)
+#define EXYNOS_SET_COLOR_MODE_WITH_RENDER_INTENT       _IOW('F', 613, struct decon_color_mode_with_render_intent_info)
+
 #endif /* ___SAMSUNG_DECON_H__ */
index ac391511c00e1e3d7030eb6eb7e96e0ef8030d04..1a539d0fc7f41d033d2e417eb2b2215729dacb65 100644 (file)
@@ -2625,6 +2625,103 @@ static int decon_get_hdr_capa_info(struct decon_device *decon,
 
 }
 
+static int decon_get_color_mode(struct decon_device *decon,
+               struct decon_color_mode_info *color_mode)
+{
+       int ret = 0;
+
+       mutex_lock(&decon->lock);
+
+       switch (color_mode->index) {
+       case 0:
+               color_mode->color_mode = HAL_COLOR_MODE_NATIVE;
+               break;
+
+       case 1:
+               color_mode->color_mode = HAL_COLOR_MODE_SRGB;
+               break;
+
+       case 2:
+               color_mode->color_mode = HAL_COLOR_MODE_DCI_P3;
+               break;
+
+       case 3:
+               color_mode->color_mode = HAL_COLOR_MODE_DISPLAY_P3;
+               break;
+
+       default:
+               decon_err("%s: queried color mode index is wrong!(%d)\n",
+                       __func__, color_mode->index);
+               ret = -EINVAL;
+               break;
+       }
+
+       decon_dbg("%s +- : %d, %d\n", __func__,
+               color_mode->index, color_mode->color_mode);
+
+       mutex_unlock(&decon->lock);
+
+       return ret;
+}
+
+static int decon_set_color_mode(struct decon_device *decon,
+               struct decon_color_mode_info *color_mode)
+{
+       int ret = 0;
+
+       decon_dbg("%s +-: %d\n", __func__, color_mode->index);
+       mutex_lock(&decon->lock);
+#if 0
+       switch (color_mode->index) {
+       case 0:
+               color_mode->color_mode = HAL_COLOR_MODE_NATIVE;
+               break;
+
+       /* TODO: add supporting color mode if necessary */
+
+       default:
+               decon_err("%s: color mode index is out of range!(%d)\n",
+                       __func__, color_mode->index);
+               ret = -EINVAL;
+               break;
+       }
+#endif
+       mutex_unlock(&decon->lock);
+
+       return ret;
+}
+
+static int decon_get_render_intent_info(struct decon_device *decon,
+               struct decon_render_intent_info *intent_info)
+{
+       int ret = 0;
+
+       mutex_lock(&decon->lock);
+
+       switch (intent_info->index) {
+       case 0:
+               intent_info->render_intent = HAL_RENDER_INTENT_COLORIMETRIC;
+               break;
+
+       case 1:
+               intent_info->render_intent = HAL_RENDER_INTENT_ENHANCE;
+               break;
+
+       default:
+               decon_err("%s: queried intent info index is wrong!(%d)\n",
+                       __func__, intent_info->index);
+               ret = -EINVAL;
+               break;
+       }
+
+       decon_dbg("%s +- : %d, %d\n", __func__,
+               intent_info->index, intent_info->render_intent);
+
+       mutex_unlock(&decon->lock);
+
+       return ret;
+}
+
 static int decon_ioctl(struct fb_info *info, unsigned int cmd,
                        unsigned long arg)
 {
@@ -2648,6 +2745,12 @@ static int decon_ioctl(struct fb_info *info, unsigned int cmd,
        u32 crc_bit, crc_start;
        u32 crc_data[2];
        u32 pwr;
+       struct decon_color_mode_info cm_info;
+       u32 cm_num;
+       struct decon_render_intents_num_info intents_num_info;
+       struct decon_render_intent_info intent_info;
+       struct decon_color_transform_info transform_info;
+       struct decon_color_mode_with_render_intent_info cm_intent_info;
 
        decon_hiber_block_exit(decon);
        switch (cmd) {
@@ -2886,6 +2989,97 @@ static int decon_ioctl(struct fb_info *info, unsigned int cmd,
                }
                break;
 
+       case EXYNOS_GET_COLOR_MODE_NUM:
+               decon_dbg("DQE: EXYNOS_GET_COLOR_MODE_NUM\n");
+               cm_num = DECON_COLOR_MODE_NUM_MAX;
+               if (copy_to_user((u32 __user *)arg, &cm_num, sizeof(u32)))
+                       ret = -EFAULT;
+               break;
+
+       case EXYNOS_GET_COLOR_MODE:
+               decon_dbg("DQE: EXYNOS_GET_COLOR_MODE\n");
+               if (copy_from_user(&cm_info, (struct decon_color_mode_info __user *)arg,
+                                  sizeof(struct decon_color_mode_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_get_color_mode(decon, &cm_info);
+               if (ret)
+                       break;
+
+               if (copy_to_user((struct decon_color_mode_info __user *)arg, &cm_info,
+                               sizeof(struct decon_color_mode_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case EXYNOS_SET_COLOR_MODE:
+               decon_dbg("DQE: EXYNOS_SET_COLOR_MODE\n");
+               if (get_user(cm_info.index, (int __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_set_color_mode(decon, &cm_info);
+               if (ret)
+                       break;
+               break;
+
+       case EXYNOS_GET_RENDER_INTENTS_NUM:
+               decon_dbg("DQE: EXYNOS_GET_RENDER_INTENTS_NUM\n");
+               intents_num_info.render_intent_num = DECON_INTENT_NUM_MAX;
+               if (copy_to_user((struct decon_render_intents_num_info __user *)arg, &intents_num_info,
+                               sizeof(struct decon_render_intents_num_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case EXYNOS_GET_RENDER_INTENT:
+               decon_dbg("DQE: EXYNOS_GET_RENDER_INTENT\n");
+               if (copy_from_user(&intent_info, (struct decon_render_intent_info __user *)arg,
+                                  sizeof(struct decon_render_intent_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_get_render_intent_info(decon, &intent_info);
+               if (ret)
+                       break;
+
+               if (copy_to_user((struct decon_render_intent_info __user *)arg, &intent_info,
+                               sizeof(struct decon_render_intent_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case EXYNOS_SET_COLOR_MODE_WITH_RENDER_INTENT:
+               if (copy_from_user(&cm_intent_info, (struct decon_color_mode_with_render_intent_info __user *)arg,
+                                  sizeof(struct decon_color_mode_with_render_intent_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               decon_dbg("DQE: EXYNOS_SET_COLOR_MOE_WITH_RENDER_INTENT: %d %d\n",
+                       cm_intent_info.color_mode, cm_intent_info.render_intent);
+               break;
+
+       case EXYNOS_SET_COLOR_TRANSFORM:
+               if (copy_from_user(&transform_info, (struct decon_color_transform_info __user *)arg,
+                                  sizeof(struct decon_color_transform_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               decon_dbg("DQE: EXYNOS_SET_COLOR_TRANSFORM: %d\n", transform_info.hint);
+#if defined(CONFIG_EXYNOS_DECON_DQE)
+               decon_dqe_set_color_transform(&transform_info);
+#endif
+               break;
+
        default:
                ret = -ENOTTY;
        }
index 39cfa1d961b27e19216ed18dad51e0d4a28f338b..da5814532464f41c0cca976ec15021d3b4c86996 100644 (file)
@@ -87,6 +87,8 @@ struct dqe_ctx {
        u32 hsc_on;
        u32 hsc_control;
        bool need_udpate;
+       u32 color_mode;
+       u32 night_light_on;
 };
 
 struct dqe_device {
@@ -152,4 +154,6 @@ void decon_dqe_enable(struct decon_device *decon);
 void decon_dqe_disable(struct decon_device *decon);
 int decon_dqe_create_interface(struct decon_device *decon);
 
+int decon_dqe_set_color_transform(struct decon_color_transform_info *transform);
+
 #endif
index 622e4631766a5b2c0c79786adb4d2cd488c9d8db..43b49d3ad7602872852a2a960b156dc48c7abea6 100644 (file)
@@ -32,6 +32,12 @@ u32 hsc_lut[35];
 int dqe_log_level = 6;
 module_param(dqe_log_level, int, 0644);
 
+const u32 nightlight_gamma_tune[3][65] = {
+       {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256},
+       {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256},
+       {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256},
+};
+
 static void dqe_load_context(void)
 {
        int i, j;
@@ -703,6 +709,110 @@ static struct attribute *dqe_attrs[] = {
 };
 ATTRIBUTE_GROUPS(dqe);
 
+static void dqe_color_transform_make_sfr(int coeff[16], int inR, int inG, int inB, int *outR, int *outG, int *outB)
+{
+       *outR = (coeff[ 0] * inR) >> 15;
+       *outR = (*outR & 0x1) ? (*outR >> 1) + 1 : *outR >> 1;
+       *outG = (coeff[ 5] * inG) >> 15;
+       *outG = (*outG & 0x1) ? (*outG >> 1) + 1 : *outG >> 1;
+       *outB = (coeff[10] * inB) >> 15;
+       *outB = (*outB & 0x1) ? (*outB >> 1) + 1 : *outB >> 1;
+}
+
+static void dqe_color_transform_night_light(int in[16], int out[16])
+{
+       int kk, jj;
+       long long int inverse_i[16] = {60847, 1269, 1269, 0, 4260, 63838, 4260, 0, 429, 429, 60007, 0, 0, 0, 0, 65536};
+
+       for (kk = 0; kk < 4; kk++)
+               for (jj = 0; jj < 4; jj++)
+                       out[kk * 4 + jj] = (inverse_i[kk * 4] * in[jj] + inverse_i[kk * 4 + 1] * in[jj + 4] + inverse_i[kk * 4 + 2] * in[jj + 8] + inverse_i[kk * 4 + 3] * in[jj + 12]) >> 16;
+}
+
+int decon_dqe_set_color_transform(struct decon_color_transform_info *transform)
+{
+       int ret = 0;
+       int i, j;
+       int temp[16];
+       struct dqe_device *dqe = dqe_drvdata;
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       mutex_lock(&dqe->lock);
+
+       if (decon) {
+               if ((decon->state == DECON_STATE_OFF) ||
+                       (decon->state == DECON_STATE_INIT)) {
+                       dqe_err("decon is not enabled!(%d)\n", decon->state);
+                       ret = -1;
+                       goto err;
+               }
+       } else {
+               dqe_err("decon is NULL!\n");
+               ret = -1;
+               goto err;
+       }
+
+
+       dqe_info("%s : color_mode=%d, hint=%d\n", __func__,
+               dqe->ctx.color_mode, transform->hint);
+
+       if (transform->matrix[0] != 65536/*transform->hint*/) {
+               for (i = 0; i < 16; i++)
+                       dqe_dbg("matrix[%d] = %d\n", i, transform->matrix[i]);
+
+               for (i = 0; i < 16; i++)
+                       temp[i] = transform->matrix[i];
+
+               dqe_color_transform_night_light(temp, transform->matrix);
+
+               for (i = 0; i < 16; i++)
+                       dqe_dbg("night[%d] = %d\n", i, transform->matrix[i]);
+       }
+
+       if (transform->matrix[0] == 65536 &&
+               transform->matrix[5] == 65536 &&
+               transform->matrix[10] == 65536)
+               dqe->ctx.night_light_on = 0;
+       else
+               dqe->ctx.night_light_on = 1;
+
+               for (i = 0; i < 3; i++)
+                       for (j = 0; j < 65; j++)
+                               gamma_lut[i][j] = nightlight_gamma_tune[i][j];
+
+       for (j = 0; j < 65; j++) {
+               int inR, inG, inB, outR, outG, outB;
+
+               inR = gamma_lut[0][j];
+               inG = gamma_lut[1][j];
+               inB = gamma_lut[2][j];
+
+               dqe_color_transform_make_sfr(transform->matrix, inR, inG, inB, &outR, &outG, &outB);
+
+               gamma_lut[0][j] = (u32)outR;
+               gamma_lut[1][j] = (u32)outG;
+               gamma_lut[2][j] = (u32)outB;
+       }
+
+       for (i = 0; i < 3; i++)
+               for (j = 0; j < 65; j++)
+                       dqe_dbg("%d ", gamma_lut[i][j]);
+
+       dqe_gamma_lut_set();
+
+       dqe->ctx.gamma_on = DQE_GAMMA_ON_MASK;
+       dqe->ctx.need_udpate = true;
+
+       dqe_restore_context();
+       decon_reg_update_req_dqe(decon->id);
+err:
+       mutex_unlock(&dqe->lock);
+
+       dqe_info("%s : ret(%d)\n", __func__, ret);
+
+       return ret;
+}
+
 void decon_dqe_enable(struct decon_device *decon)
 {
        u32 val;