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];
};
/* 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__ */
}
+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)
{
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) {
}
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;
}
u32 hsc_on;
u32 hsc_control;
bool need_udpate;
+ u32 color_mode;
+ u32 night_light_on;
};
struct dqe_device {
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
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;
};
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;