From: Andrzej Hajda Date: Tue, 6 Sep 2016 09:35:03 +0000 (+0200) Subject: drm/panel: add Samsung Dynamic AID helpers X-Git-Tag: submit/tizen/20160926.022655~23 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0ba9b4524a68a31d6657ad957391a391d51b1dac;p=platform%2Fkernel%2Flinux-exynos.git drm/panel: add Samsung Dynamic AID helpers Dynamic AMOLED Impulse Driving helpers allow to calculate gamma tables for different brightness levels based on tables specific for given model of display panel and values written in MTP memory of the panel. Change-Id: I98de87d78b481f3369ea9952df058126ec513e9b Signed-off-by: Andrzej Hajda --- diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 1875e69466b3..a0ca9bdb0e00 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -54,5 +54,9 @@ config DRM_PANEL_S6E3HA2 depends on OF select DRM_MIPI_DSI select VIDEOMODE_HELPERS + select DRM_PANEL_SAMSUNG_DYNAMIC_AID + +config DRM_PANEL_SAMSUNG_DYNAMIC_AID + bool endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 7bd7b84751f6..5063f9129d87 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o obj-$(CONFIG_DRM_PANEL_S6E63J0X03) += panel-s6e63j0x03.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_S6E3HA2) += panel-s6e3ha2.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_DYNAMIC_AID) += samsung-dynamic_aid.o diff --git a/drivers/gpu/drm/panel/samsung-dynamic_aid.c b/drivers/gpu/drm/panel/samsung-dynamic_aid.c new file mode 100644 index 000000000000..ff58588bee9e --- /dev/null +++ b/drivers/gpu/drm/panel/samsung-dynamic_aid.c @@ -0,0 +1,331 @@ +/* + * Dynamic AMOLED Impulse Driving (DAID) helper functions. + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd + * + * Andrzej Hajda + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#include "samsung-dynamic_aid.h" + +static const u8 daid_gcp[] = { + 0, 3, 11, 23, 35, 51, 87, 151, 203, 255 +}; + +static const int daid_vt_coefficient[] = { + 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 138, 148, 158, 168, 178, 186 +}; + +static const int daid_gamma_formula_mods[2][2] = { + {64, 320}, /* V1 - V203 */ + {72, 860}, /* V255, VT */ +}; + +static const int daid_gamma_default[] = { + 0x80, /* V1 - V203 */ + 0x100, /* V255 */ +}; + +/* Gamma Curve Tables */ + +static const int daid_gct_2p15[DAID_VOUT_COUNT] = { + 0, 7, 30, 71, 132, 213, 315, 439, + 586, 754, 946, 1161, 1400, 1663, 1950, 2262, + 2599, 2961, 3348, 3761, 4199, 4663, 5154, 5671, + 6214, 6784, 7381, 8005, 8656, 9335, 10040, 10774, + 11535, 12324, 13141, 13986, 14859, 15761, 16691, 17649, + 18637, 19653, 20698, 21772, 22875, 24007, 25169, 26360, + 27581, 28831, 30111, 31421, 32760, 34130, 35529, 36959, + 38419, 39909, 41429, 42980, 44562, 46174, 47817, 49490, + 51195, 52930, 54696, 56494, 58322, 60182, 62073, 63995, + 65948, 67933, 69950, 71998, 74078, 76189, 78333, 80508, + 82715, 84954, 87224, 89528, 91863, 94230, 96630, 99062, + 101526, 104022, 106552, 109113, 111708, 114334, 116994, 119686, + 122411, 125169, 127960, 130784, 133641, 136530, 139453, 142409, + 145399, 148421, 151477, 154566, 157688, 160844, 164034, 167257, + 170513, 173803, 177127, 180484, 183875, 187300, 190759, 194252, + 197778, 201339, 204933, 208562, 212224, 215921, 219652, 223417, + 227217, 231050, 234918, 238821, 242757, 246729, 250734, 254775, + 258849, 262959, 267103, 271282, 275495, 279743, 284026, 288344, + 292697, 297084, 301507, 305964, 310457, 314984, 319547, 324145, + 328778, 333446, 338149, 342888, 347661, 352471, 357315, 362195, + 367110, 372061, 377047, 382069, 387126, 392219, 397348, 402512, + 407712, 412948, 418219, 423526, 428869, 434248, 439663, 445113, + 450600, 456122, 461681, 467275, 472906, 478572, 484275, 490014, + 495789, 501600, 507448, 513332, 519252, 525208, 531201, 537230, + 543296, 549398, 555536, 561711, 567923, 574171, 580455, 586777, + 593134, 599529, 605960, 612428, 618933, 625474, 632052, 638668, + 645319, 652008, 658734, 665497, 672296, 679133, 686006, 692917, + 699865, 706850, 713872, 720931, 728027, 735160, 742331, 749539, + 756784, 764066, 771386, 778743, 786138, 793569, 801039, 808545, + 816089, 823671, 831290, 838947, 846641, 854373, 862143, 869950, + 877794, 885677, 893597, 901555, 909550, 917584, 925655, 933764, + 941911, 950095, 958318, 966578, 974877, 983213, 991588, 1000000 +}; + +static const int daid_gct_2p20[DAID_VOUT_COUNT] = { + 0, 5, 23, 57, 107, 175, 262, 367, + 493, 638, 805, 992, 1202, 1433, 1687, 1963, + 2263, 2586, 2932, 3303, 3697, 4116, 4560, 5028, + 5522, 6041, 6585, 7155, 7751, 8373, 9021, 9696, + 10398, 11126, 11881, 12664, 13473, 14311, 15175, 16068, + 16988, 17936, 18913, 19918, 20951, 22013, 23104, 24223, + 25371, 26549, 27755, 28991, 30257, 31551, 32876, 34230, + 35614, 37029, 38473, 39947, 41452, 42987, 44553, 46149, + 47776, 49433, 51122, 52842, 54592, 56374, 58187, 60032, + 61907, 63815, 65754, 67725, 69727, 71761, 73828, 75926, + 78057, 80219, 82414, 84642, 86901, 89194, 91518, 93876, + 96266, 98689, 101145, 103634, 106156, 108711, 111299, 113921, + 116576, 119264, 121986, 124741, 127530, 130352, 133209, 136099, + 139022, 141980, 144972, 147998, 151058, 154152, 157281, 160444, + 163641, 166872, 170138, 173439, 176774, 180144, 183549, 186989, + 190463, 193972, 197516, 201096, 204710, 208360, 212044, 215764, + 219520, 223310, 227137, 230998, 234895, 238828, 242796, 246800, + 250840, 254916, 259027, 263175, 267358, 271577, 275833, 280124, + 284452, 288816, 293216, 297653, 302125, 306635, 311180, 315763, + 320382, 325037, 329729, 334458, 339223, 344026, 348865, 353741, + 358654, 363604, 368591, 373615, 378676, 383775, 388910, 394083, + 399293, 404541, 409826, 415148, 420508, 425905, 431340, 436813, + 442323, 447871, 453456, 459080, 464741, 470440, 476177, 481952, + 487765, 493616, 499505, 505432, 511398, 517401, 523443, 529523, + 535642, 541798, 547994, 554227, 560499, 566810, 573159, 579547, + 585973, 592438, 598942, 605484, 612066, 618686, 625345, 632043, + 638779, 645555, 652370, 659224, 666117, 673049, 680020, 687031, + 694081, 701170, 708298, 715465, 722672, 729919, 737205, 744530, + 751895, 759300, 766744, 774227, 781751, 789314, 796917, 804559, + 812241, 819964, 827726, 835528, 843370, 851252, 859174, 867136, + 875138, 883180, 891262, 899385, 907547, 915750, 923993, 932277, + 940601, 948965, 957370, 965815, 974300, 982826, 991393, 1000000 +}; + +static int daid_bits_to_int(const u8* data, int bit_start, int bit_len) +{ + int o = bit_start / 8, ob = bit_start % 8; + int val, sign; + + switch (bit_len) { + case 4: + val = (data[o] >> ob) & 0x7; + sign = data[o] & BIT(ob + 3); + break; + case 8: + return (char)data[o]; + case 9: + val = data[o + 1]; + sign = data[o] & 1; + } + + return sign ? -val : val; +} + +static void daid_int_to_bits(u8* data, int bit_start, int bit_len, int val) +{ + int o = bit_start / 8, ob = bit_start % 8; + + switch (bit_len) { + case 4: + data[o] &= ~(0xf << ob); + data[o] |= val << ob; + break; + case 8: + data[o] = (u8)val; + break; + case 9: + data[o] = (val & 0x100) ? 1 : 0; + data[o + 1] = val; + } +} + +static void daid_params_to_array(daid_rgb *arr, const u8 *d) +{ + int i, j; + + for (j = 0; j < 3; ++j) { + arr[0][j] = daid_bits_to_int(&d[DAID_PARAM_COUNT - 2], + 4 * j, 4); + arr[DAID_GCP_COUNT - 1][j] = daid_bits_to_int(&d[2 * j], 0, 9); + } + + for (i = 1; i < DAID_GCP_COUNT - 1; ++i) + for (j = 0; j < 3; ++j) + arr[i][j] = daid_bits_to_int( + &d[DAID_PARAM_COUNT - 5 - 3 * i + j], 0, 8); +} + +static void daid_array_to_params(u8 *d, daid_rgb *arr) +{ + int i, j; + + for (j = 0; j < 3; ++j) { + daid_int_to_bits(&d[DAID_PARAM_COUNT - 2], 4 * j, 4, arr[0][j]); + daid_int_to_bits(&d[2 * j], 0, 9, arr[DAID_GCP_COUNT - 1][j]); + d[3 * DAID_GCP_COUNT + j] = 0; + } + + for (i = 1; i < DAID_GCP_COUNT - 1; ++i) + for (j = 0; j < 3; ++j) + daid_int_to_bits(&d[DAID_PARAM_COUNT - 5 - 3 * i + j], + 0, 8, arr[i][j]); +} + +struct daid_ctx { + struct daid_cfg cfg; + daid_rgb mtp[DAID_GCP_COUNT]; + daid_rgb vgcp[DAID_GCP_COUNT]; + daid_rgb vout[DAID_VOUT_COUNT]; +}; + +static void daid_calc_vgcp(struct daid_ctx *ctx) +{ + int vref, vdiff; + int i = 0, j; + const int v0 = ctx->cfg.vreg_out * 100; + daid_rgb *v = ctx->vgcp; + const int i_max = DAID_GCP_COUNT - 1; + + /* VT is calculated differently */ + for (j = 0; j < 3; ++j) { + vdiff = v0 * daid_vt_coefficient[ctx->mtp[0][j]]; + v[0][j] = v0 - vdiff / daid_gamma_formula_mods[1][1]; + } + + for (i = i_max; i > 0; --i) { + const int *m = daid_gamma_formula_mods[i == i_max]; + const int gamma = daid_gamma_default[i == i_max]; + + for (j = 0; j < 3; ++j) { + if (i == 1 || i == i_max) + vref = v0; + else + vref = v[0][j]; + vdiff = vref; + if (i < i_max) + vdiff -= v[i + 1][j]; + vdiff *= gamma + ctx->mtp[i][j] + m[0]; + v[i][j] = vref - vdiff / m[1]; + } + } +} + +static void daid_calc_vout(struct daid_ctx *ctx) +{ + int i, j, k, ke, uninitialized_var(dk); + daid_rgb dv, v; + daid_rgb *ov = ctx->vout; + + for (j = 0; j < 3; ++j) + ov[0][j] = v[j] = ctx->cfg.vreg_out * 100; + + for (k = 1, i = 0, ke = 0; k < DAID_VOUT_COUNT; ++k) { + if (k > ke) { + ke = daid_gcp[++i]; + dk = ke - daid_gcp[i - 1]; + for (j = 0; j < 3; ++j) { + dv[j] = ctx->vgcp[i][j] - v[j]; + v[j] = ctx->vgcp[i][j]; + } + } + for (j = 0; j < 3; ++j) + ov[k][j] = v[j] - dv[j] * (ke - k) / dk; + } +} + +static int daid_get_lut_index(int val) +{ + const int *begin = daid_gct_2p20, *end = begin + DAID_VOUT_COUNT; + const int *b = begin, *e = end; + + while (e - b > 1) { + const int *m = b + (e - b) / 2; + if (val >= *m) + b = m; + else + e = m; + } + + if ((e < end) && (val - *b > *e - val)) + b = e; + + return b - begin; +} + +static void daid_calc_vmgcp(struct daid_ctx *ctx, daid_rgb *mv, int ibr) +{ + const int nit = ctx->cfg.nits[ibr]; + const int *gct = nit < ctx->cfg.nit_gct ? daid_gct_2p15 : daid_gct_2p20; + const int nit_max = ctx->cfg.nits[ctx->cfg.nits_count - 1]; + int i, j; + + for (j = 0; j < 3; ++j) + mv[0][j] = ctx->vgcp[0][j]; + + for (i = 1; i < DAID_GCP_COUNT; ++i) { + int l = ctx->cfg.brightness_base[ibr] * gct[daid_gcp[i]] + / nit_max; + int gv = daid_get_lut_index(l) + ctx->cfg.gradation[ibr][i]; + for (j = 0; j < 3; ++j) + mv[i][j] = ctx->vout[gv][j]; + } + +} + +static void daid_calc_gamma(struct daid_ctx *ctx, daid_rgb *g, int ibr) +{ + int v0, vref, vdiff; + int i = 0, j, gt; + const int i_max = DAID_GCP_COUNT - 1; + daid_rgb mv[DAID_GCP_COUNT]; + + daid_calc_vmgcp(ctx, mv, ibr); + + v0 = ctx->cfg.vreg_out * 100; + + for (i = i_max; i > 0; --i) { + const int *m = daid_gamma_formula_mods[i == i_max]; + + for (j = 0; j < 3; ++j) { + vref = (i == 1 || i == i_max) ? v0 : ctx->vgcp[0][j]; + vdiff = (i < i_max) ? (vref - mv[i + 1][j]) : vref; + vref -= mv[i][j]; + gt = (vref + 1) * m[1] / vdiff - m[0]; + gt += ctx->cfg.color_offset[ibr][i][j] - ctx->mtp[i][j]; + if (gt > 255 && i != i_max) + gt = 255; + g[i][j] = gt; + } + } + for (j = 0; j < 3; ++j) + g[0][j] = 0; +} + +int daid_calc_gammodes(u8 (*gamma)[DAID_PARAM_COUNT], + struct daid_cfg *cfg, u8 *mtp) +{ + struct daid_ctx *ctx; + daid_rgb g[DAID_GCP_COUNT]; + int i; + + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->cfg = *cfg; + daid_params_to_array(ctx->mtp, mtp); + daid_calc_vgcp(ctx); + daid_calc_vout(ctx); + for (i = 0; i < cfg->nits_count; ++i) { + daid_calc_gamma(ctx, g, i); + daid_array_to_params(gamma[i], g); + pr_debug("Gamma[%d]: %*ph\n", i, DAID_PARAM_COUNT, gamma[i]); + } + + kfree(ctx); + + return 0; +} diff --git a/drivers/gpu/drm/panel/samsung-dynamic_aid.h b/drivers/gpu/drm/panel/samsung-dynamic_aid.h new file mode 100644 index 000000000000..670f4c898d43 --- /dev/null +++ b/drivers/gpu/drm/panel/samsung-dynamic_aid.h @@ -0,0 +1,37 @@ +#ifndef __DRM_PANEL_SAMSUNG_DYNAMIC_AID_H__ +#define __DRM_PANEL_SAMSUNG_DYNAMIC_AID_H__ +/* + * Dynamic AMOLED Impulse Driving (DAID) helper functions. + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd + * + * Andrzej Hajda + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +/* GCP - gamma control points */ +#define DAID_GCP_COUNT 10 +#define DAID_VOUT_COUNT 256 +#define DAID_PARAM_COUNT (3 * (DAID_GCP_COUNT + 1) + 2) + +typedef int daid_rgb[3]; + +struct daid_cfg { + int vreg_out; + const int *nits; + int nits_count; + int nit_gct; + const int *brightness_base; + const int (*gradation)[DAID_GCP_COUNT]; + const daid_rgb (*color_offset)[DAID_GCP_COUNT]; +}; + +int daid_calc_gammodes(u8 (*gamma)[DAID_PARAM_COUNT], + struct daid_cfg *cfg, u8 *mtp); + +#endif