diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index ed05b131ed3a..65acc2170875 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -329,6 +329,7 @@ i915-y += \ display/intel_dp.o \ display/intel_dp_aux.o \ display/intel_dp_aux_backlight.o \ + display/intel_dp_legacy_oled_brightness.o \ display/intel_dp_hdcp.o \ display/intel_dp_link_training.o \ display/intel_dp_mst.o \ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 99a6fd2900b9..92c56485e2b8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -50,6 +50,7 @@ #include "intel_display_power.h" #include "intel_dpll_mgr.h" #include "intel_wm_types.h" +#include "intel_dp_legacy_oled_brightness.h" struct cec_notifier; struct drm_printer; @@ -423,6 +424,9 @@ struct intel_panel { bool supports_sdp_colorimetry; bool supports_tone_mapping; } intel_cap; + struct { + struct intel_legacy_panel_data panel_data; + } legacy; } edp; struct backlight_device *device; diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index 8173de8aec63..2ddbf170cb1c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -41,6 +41,7 @@ #include "intel_display_core.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dp_legacy_oled_brightness.h" #include "intel_dp_aux_backlight.h" /* @@ -101,6 +102,7 @@ enum intel_dp_aux_backlight_modparam { INTEL_DP_AUX_BACKLIGHT_ON = 1, INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2, INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3, + INTEL_DP_AUX_BACKLIGHT_LEGACY = 99, }; static bool is_intel_tcon_cap(const u8 tcon_cap[4]) @@ -702,7 +704,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) struct intel_dp *intel_dp = intel_attached_dp(connector); struct drm_device *dev = connector->base.dev; struct intel_panel *panel = &connector->panel; - bool try_intel_interface = false, try_vesa_interface = false; + bool try_intel_interface = false, try_vesa_interface = false, try_legacy_interface = false; /* Check the VBT and user's module parameters to figure out which * interfaces to probe @@ -734,6 +736,9 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL: try_intel_interface = true; break; + case INTEL_DP_AUX_BACKLIGHT_LEGACY: + try_legacy_interface = true; + break; } /* For eDP 1.5 and above we are supposed to use VESA interface for brightness control */ @@ -768,5 +773,10 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) return 0; } + if (try_legacy_interface && intel_dp_aux_legacy_brightness_supported(connector)) { + panel->backlight.funcs = intel_dp_aux_legacy_get_bl_funcs(); + return 0; + } + return -ENODEV; } diff --git a/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.c b/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.c new file mode 100644 index 000000000000..3071f5b60940 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Chris Xiong + */ + +#include "intel_backlight.h" +#include "intel_display_core.h" +#include "intel_display_types.h" +#include "intel_dp.h" +#include "intel_dp_legacy_oled_brightness.h" +#include "linux/firmware.h" +#include "linux/slab.h" +#include "linux/stdarg.h" + +static bool intel_dp_aux_legacy_write_sequence(struct drm_dp_aux *aux, + const u32 *address_seq, + const u8 *value_seq, + size_t length) +{ + size_t p; + + for (p = 0; p < length; ++p) { + drm_dbg_kms(aux->drm_dev, "%s: writing 0x%02x to 0x%x", __func__, value_seq[p], + address_seq[p]); + if (drm_dp_dpcd_writeb(aux, address_seq[p], value_seq[p]) < 1) + return false; + } + return true; +} + +static bool intel_dp_aux_legacy_write_sequence_var(struct drm_dp_aux *aux, + const u32 *address_seq, + const u8 *value_seq, + size_t length, + size_t nparameters, ...) +{ + u8 *value_buf = NULL; + va_list args; + bool ret = false; + int pos, val; + size_t p; + + if (!nparameters) + return intel_dp_aux_legacy_write_sequence(aux, address_seq, value_seq, length); + value_buf = kmalloc(length, GFP_KERNEL); + memcpy(value_buf, value_seq, length); + + va_start(args, nparameters); + for (p = 0; p < nparameters; ++p) { + pos = va_arg(args, int); + val = va_arg(args, int); + if (pos >= 0 && pos < length) + value_buf[pos] = val; + } + va_end(args); + ret = intel_dp_aux_legacy_write_sequence(aux, address_seq, value_buf, length); + + kfree(value_buf); + return ret; +} + +static bool intel_dp_aux_legacy_handshake(struct intel_connector *connector) +{ + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + struct drm_dp_aux *aux = &intel_dp->aux; + char *handshake_str = "PARAAUX-REG"; + u8 v, i, retries; + int ret; + + ret = drm_dp_dpcd_readb(aux, 0x490, &v); + if (ret < 1) { + drm_info(display->drm, "%s: read dpcd register 0x490 failed: %d", __func__, ret); + } else { + if (v != 1) { + for (retries = 0; retries < 20; ++retries) { + for (i = 0; i < 11; ++i) { + ret = drm_dp_dpcd_writeb(aux, 0x490, (u8)handshake_str[i]); + if (ret < 1) + break; + } + ret = drm_dp_dpcd_readb(aux, 0x490, &v); + if (ret == 1 && v == 1) + return true; + } + } else { + return true; + } + } + drm_err(display->drm, "%s: handshake failed", __func__); + return false; +} + +static void intel_dp_aux_legacy_get_elvss_max_offset(struct intel_connector *connector) +{ + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + struct drm_dp_aux *aux = &intel_dp->aux; + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + const u32 address_seq1[11] = {0x491, 0x492, 0x493, 0x491, 0x492, 0x493, 0x492, 0x493, + 0x492, 0x493, 0x492}; + const u8 value_seq1[11] = { 0x02, 0x7f, 0x01, 0x07, 0xff, 0x04, 0x03, 0x04, + 0x06, 0x26, 0x0a}; + + if (intel_dp_aux_legacy_handshake(connector)) { + if (!intel_dp_aux_legacy_write_sequence(aux, address_seq1, value_seq1, 11)) { + drm_err(display->drm, "%s: write failed", __func__); + return; + } + if (drm_dp_dpcd_readb(aux, 0x493, &panel_data->elvss_max_offset) < 1) { + drm_err(display->drm, "%s: read failed", __func__); + return; + } + drm_dbg_kms(display->drm, "%s: ELVSS max offset: %d", __func__, + (int)panel_data->elvss_max_offset); + } else { + drm_err(display->drm, "%s: handshake failed", __func__); + } +} + +static bool intel_dp_aux_legacy_get_tcon_gamma(struct intel_connector *connector) +{ + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + struct drm_dp_aux *aux = &intel_dp->aux; + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + struct intel_legacy_panel_data_intermediate *interm = panel_data->intermediates; + + const u32 address_seq1[6] = {0x491, 0x492, 0x493, 0x491, 0x492, 0x493}; + const u8 value_seq1[6] = { 0x2, 0x7f, 0x1, 0x7, 0xff, 0x4}; + const u32 address_seq2[8] = {0x492, 0x493, 0x492, 0x493, 0x492, 0x493, 0x491, 0x492}; + const u8 value_seq2[8] = { 0x0, 0, 0x1, 0, 0x2, 0, 0x7, 0xc}; + u16 i, j, k; + + if (!intel_dp_aux_legacy_handshake(connector)) { + drm_err(display->drm, "%s: handshake failed", __func__); + return false; + } + if (!intel_dp_aux_legacy_write_sequence(aux, address_seq1, value_seq1, 6)) { + drm_err(display->drm, "%s: write failed", __func__); + return false; + } + if (!interm) { + drm_err(display->drm, "%s: could not get hold of intermediate data", __func__); + return false; + } + for (i = 0; i < 0x20; ++i) { + k = i * 0xb; + for (j = 0; j <= 0x20; ++j) { + intel_dp_aux_legacy_write_sequence_var(aux, address_seq2, + value_seq2, 8, 3, + 1, 1 << ((j / 11) + 1), + 3, (u8)(k << 7), + 5, (u8)(k >> 1)); + if (i == 0 && j == 0) + udelay(100); + drm_dp_dpcd_readb(aux, 0x493, &interm->tcon_gamma[i][j]); + if (++k >= (i + 1) * 0xb) + k = i * 0xb; + } + } + + u16 *vp = &interm->gamma_values[0][0]; + u8 *gp = &interm->tcon_gamma[0][0]; + + for (i = 0; i < 0x20 ; ++i) { + for (j = 0; j <= 0x20; ++j) { + switch (j) { + case 0x7: case 0x12: case 0x1d: + *vp = (u16)(*(gp + 2) & 0x80) * 2 | *gp; + break; + case 0x9: case 0x14: case 0x1f: + *vp = *gp & 0x7f; + break; + case 0xa: case 0x15: case 0x20: + *vp = *gp & 0xf; + break; + default: + *vp = *gp; + } + ++vp; + ++gp; + } + } + return true; +} + +static void intel_dp_aux_legacy_write_brightness(struct intel_connector *connector, u8 brightness) +{ + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + struct drm_dp_aux *aux = &intel_dp->aux; + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + u8 *brightness_gamma = panel_data->interpolated_gamma[100 - brightness]; + u32 *write_addr_buf = NULL; + u8 *write_val_buf = NULL; + const u32 address_seq1[7] = {0x491, 0x492, 0x493, 0x492, 0x493, 0x492, 0x493}; + const u8 value_seq1[7] = { 0x0f, 0xff, 0x00, 0x9d, 0, 0x9b, 0}; + const u32 address_seq2[7] = {0x491, 0x492, 0x493, 0x492, 0x493, 0x492, 0x493}; + const u8 value_seq2[7] = { 0x0f, 0xff, 0x02, 0x30, 0, 0x33, 0}; + const u32 address_seq3[7] = {0x491, 0x492, 0x493, 0x492, 0x493, 0x492, 0x493}; + const u8 value_seq3[7] = { 0x0e, 0x80, 0, 0x90, 0, 0x91, 0}; + const u32 address_seq4[6] = {0x491, 0x492, 0x493, 0x491, 0x492, 0x493}; + const u8 value_seq4[6] = { 0x02, 0x7f, 0x01, 0x07, 0xff, 0x04}; + const u32 address_seq5[14] = {0x492, 0x493, 0x491, 0x492, 0x493, 0x491, 0x492, + 0x493, 0x492, 0x493, 0x491, 0x492, 0x493, 0x491}; + const u8 value_seq5[14] = { 0x32, 0x01, 0x02, 0xeb, 0x91, 0x09, 0xf0, + 0xef, 0xf9, 0, 0x02, 0xeb, 0x96, 0x0e}; + u16 i, acl_data; + + if (!intel_dp_aux_legacy_handshake(connector)) { + drm_err(display->drm, "%s: handshake failed", __func__); + return; + } + drm_dbg_kms(display->drm, "%s: new brightness: %3d", __func__, brightness); + + if (!intel_dp_aux_legacy_write_sequence_var(aux, address_seq1, value_seq1, 7, 2, + 4, panel_data->aor_buf[brightness * 2], + 6, panel_data->aor_buf[brightness * 2 + 1])) + goto fail; + + if (!intel_dp_aux_legacy_write_sequence_var(aux, address_seq2, value_seq2, 7, 2, + 4, panel_data->delvss[brightness], + 6, panel_data->elvss_max_offset)) + goto fail; + + if (brightness > panel_data->brightness_for_acl) { + acl_data = __le16_to_cpu(((u16 *)panel_data->acl_cutoff_and_delta_buf) + [brightness - panel_data->brightness_for_acl - 1]); + if (!intel_dp_aux_legacy_write_sequence_var(aux, address_seq3, value_seq3, 7, 3, + 2, 0x90, + 4, acl_data & 0xff, + 6, acl_data >> 8)) + goto fail; + } else { + if (!intel_dp_aux_legacy_write_sequence_var(aux, address_seq3, value_seq3, + 3, 1, 2, 0x80)) + goto fail; + } + + if (!intel_dp_aux_legacy_write_sequence(aux, address_seq4, value_seq4, 6)) + goto fail; + drm_dbg_kms(display->drm, "brightness_gamma @ %d: %*ph\n", 100 - brightness, 33, + brightness_gamma); + write_addr_buf = kmalloc_array(0x21 * 2, 4, GFP_KERNEL); + write_val_buf = kmalloc_array(0x21 * 2, 1, GFP_KERNEL); + for (i = 0; i <= 0x20; ++i) { + write_addr_buf[i * 2] = 0x492; + write_addr_buf[i * 2 + 1] = 0x493; + write_val_buf[i * 2] = i + 0x10; + if (i == 10 || i == 21 || i == 32) + write_val_buf[i * 2 + 1] = brightness_gamma[i] & 0xf; + else + write_val_buf[i * 2 + 1] = brightness_gamma[i]; + } + if (!intel_dp_aux_legacy_write_sequence(aux, write_addr_buf, write_val_buf, 0x21 * 2)) + goto fail; + udelay(1000); + if (!intel_dp_aux_legacy_write_sequence_var(aux, address_seq5, value_seq5, 14, 1, + 9, panel_data->SP[brightness])) + goto fail; + for (i = 0; i < 9; ++i) { + //reuse current data in write_addr_buf + //as well as values written to 0x492 + write_val_buf[i * 2 + 1] = panel_data->IRC[brightness][i]; + } + if (!intel_dp_aux_legacy_write_sequence(aux, write_addr_buf, write_val_buf, 9 * 2)) + goto fail; + kfree(write_addr_buf); + kfree(write_val_buf); + return; +fail: + kfree(write_addr_buf); + kfree(write_val_buf); + drm_err(display->drm, "%s: failed to write dpcd registers", __func__); +} + +inline s16 sign(s16 v) { return v < 0 ? -1 : 1; } + +static void intel_dp_aux_legacy_calculate_interpolated_values(struct intel_connector *connector) +{ + struct intel_display *display = to_intel_display(connector); + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + struct intel_legacy_panel_data_intermediate *interm = panel_data->intermediates; + + s16 dv; + u8 old_d; + u8 base, delta, multiplier, bias, attenuation; + u16 i, j, br; + + for (i = 0; i <= 0x20; ++i) { + old_d = 0xff; + for (br = 0; br <= 100; ++br) { + base = interm->interpolation[br][0]; + delta = interm->interpolation[br][1]; + multiplier = interm->interpolation[br][2]; + bias = interm->interpolation[br][3]; + attenuation = interm->interpolation[br][4]; + if (old_d != delta) { + dv = interm->gamma_values[delta][i] - + interm->gamma_values[delta + 1][i]; + old_d = delta; + } + if (unlikely(attenuation == 0)) + attenuation = 1; + interm->interpolated_values[br][i] = + interm->gamma_values[base][i] + + sign(dv) * (abs(dv * multiplier) + bias) / attenuation; + } + } + + u8 *pint_gamma = &panel_data->interpolated_gamma[0][0]; + u16 *pint_values = &interm->interpolated_values[0][0]; + + for (i = 0; i < 101; ++i) { + for (j = 0; j <= 32; ++j) { + switch (j) { + case 9: case 20: case 31: + *pint_gamma = + (((u8)*(pint_values - 2) >> 1 ^ (u8)*pint_values) & 0x7f) ^ + (u8)(*(pint_values - 2) >> 1); + break; + case 10: case 21: case 32: + *pint_gamma = (u8)*pint_values & 0xf; + break; + default: + *pint_gamma = (u8)*pint_values; + } + ++pint_gamma; + ++pint_values; + } + } + for (i = 0; i < 101; ++i) + drm_dbg_kms(display->drm, "interpolated gamma %3d %*phN", + i, 33, panel_data->interpolated_gamma[i]); +} + +static bool fw_read_data(const struct firmware *fw, + const u8 **read_ptr, + void *output, + u32 expected_length) +{ + if (fw->size - (*read_ptr - fw->data) < expected_length) + return false; + memcpy(output, *read_ptr, expected_length); + *read_ptr += expected_length; + return true; +} + +static bool fw_read_array(const struct firmware *fw, + const u8 **read_ptr, + void *output, + u32 max_length) +{ + u16 len; + + if (!fw_read_data(fw, read_ptr, &len, 2)) + return false; + len = __le16_to_cpu(len); + if (len > max_length) + return false; + return fw_read_data(fw, read_ptr, output, len); +} + +static int intel_dp_aux_legacy_load_panel_properties(struct intel_connector *connector) +{ + struct intel_display *display = to_intel_display(connector); + struct device *dev = connector->encoder->base.dev->dev; + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + struct intel_legacy_panel_data_intermediate *interm = panel_data->intermediates; + int ret; + const struct firmware *fw; + const u8 *pdata; + + ret = request_firmware(&fw, "intel_legacy_panel_data.bin", dev); + if (ret < 0) + return ret; + ret = 0; + pdata = fw->data; + + if (!fw_read_array(fw, &pdata, panel_data->aor_buf, 202)) + goto fail_invalid_data; + if (!fw_read_array(fw, &pdata, panel_data->delvss, 101)) + goto fail_invalid_data; + + if (!fw_read_data(fw, &pdata, &panel_data->brightness_for_acl, 2)) + goto fail_invalid_data; + panel_data->brightness_for_acl = __le16_to_cpu(panel_data->brightness_for_acl); + + if (!fw_read_array(fw, &pdata, panel_data->acl_cutoff_and_delta_buf, 200)) + goto fail_invalid_data; + if (!fw_read_array(fw, &pdata, panel_data->IRC, 909)) + goto fail_invalid_data; + if (!fw_read_array(fw, &pdata, panel_data->SP, 101)) + goto fail_invalid_data; + if (!fw_read_array(fw, &pdata, interm->interpolation, 505)) + goto fail_invalid_data; + + release_firmware(fw); + return ret; +fail_invalid_data: + release_firmware(fw); + drm_err(display->drm, "invalid intel_legacy_panel_data.bin"); + return -EINVAL; +} + +static int intel_dp_aux_legacy_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + int ret; + + panel_data->intermediates = kzalloc(sizeof(struct intel_legacy_panel_data_intermediate), + GFP_KERNEL); + if (!panel_data->intermediates) { + ret = -ENOMEM; + goto fail; + } + ret = intel_dp_aux_legacy_load_panel_properties(connector); + if (ret < 0) + goto fail; + panel->backlight.max = 100; + panel->backlight.min = 0; + panel->backlight.level = 100; + if (!intel_dp_aux_legacy_handshake(connector)) { + ret = -ENODEV; + goto fail; + } + intel_dp_aux_legacy_get_elvss_max_offset(connector); + if (!intel_dp_aux_legacy_get_tcon_gamma(connector)) { + ret = -ENODEV; + goto fail; + } + intel_dp_aux_legacy_calculate_interpolated_values(connector); + panel_data->values_initialized = true; + ret = 0; +fail: + kfree(panel_data->intermediates); + panel_data->intermediates = NULL; + return ret; +} +static void intel_dp_aux_legacy_disable_backlight(const struct drm_connector_state *old_conn_state, + u32 level) +{ + struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + + if (!panel_data->values_initialized) + intel_dp_aux_legacy_setup_backlight(connector, PIPE_A); + intel_dp_aux_legacy_write_brightness(connector, 0); +} +static void +intel_dp_aux_legacy_enable_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + + if (level > 100) + level = 100; + panel->backlight.level = level; + if (!panel_data->values_initialized) + intel_dp_aux_legacy_setup_backlight(connector, PIPE_A); + intel_dp_aux_legacy_write_brightness(connector, level); +} +static u32 intel_dp_aux_legacy_get_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct intel_panel *panel = &connector->panel; + + return panel->backlight.level; +} +static void +intel_dp_aux_legacy_set_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_panel *panel = &connector->panel; + struct intel_legacy_panel_data *panel_data = &panel->backlight.edp.legacy.panel_data; + + if (level > 100) + level = 100; + panel->backlight.level = level; + if (!panel_data->values_initialized) + intel_dp_aux_legacy_setup_backlight(connector, PIPE_A); + intel_dp_aux_legacy_write_brightness(connector, level); +} + +static const struct intel_panel_bl_funcs intel_dp_aux_legacy_bl_funcs = { + .setup = intel_dp_aux_legacy_setup_backlight, + .enable = intel_dp_aux_legacy_enable_backlight, + .disable = intel_dp_aux_legacy_disable_backlight, + .set = intel_dp_aux_legacy_set_backlight, + .get = intel_dp_aux_legacy_get_backlight, +}; + +const struct intel_panel_bl_funcs *intel_dp_aux_legacy_get_bl_funcs(void) +{ + return &intel_dp_aux_legacy_bl_funcs; +} +bool intel_dp_aux_legacy_brightness_supported(struct intel_connector *connector) +{ + return intel_dp_aux_legacy_handshake(connector); +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.h b/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.h new file mode 100644 index 000000000000..16f1f5185121 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Chris Xiong + */ + +#ifndef __INTEL_DP_LEGACY_OLED_BRIGHTNESS_H__ +#define __INTEL_DP_LEGACY_OLED_BRIGHTNESS_H__ + +#include + +struct intel_connector; +struct intel_panel_bl_funcs; + +struct intel_legacy_panel_data_intermediate { + u8 interpolation[101][5]; + + u16 gamma_values[32][33]; + u16 interpolated_values[101][33]; + u8 tcon_gamma[32][33]; +}; + +struct intel_legacy_panel_data { + //registry values + u8 aor_buf[202]; // u16[101] + u8 delvss[101]; + u16 brightness_for_acl; + u8 acl_cutoff_and_delta_buf[200]; // u16[100] + u8 IRC[101][9]; + u8 SP[101]; + + u8 interpolated_gamma[101][33]; + u8 elvss_max_offset; + bool values_initialized; + struct intel_legacy_panel_data_intermediate *intermediates; +}; + +const struct intel_panel_bl_funcs *intel_dp_aux_legacy_get_bl_funcs(void); +bool intel_dp_aux_legacy_brightness_supported(struct intel_connector *connector); + +#endif /* __INTEL_DP_LEGACY_OLED_BRIGHTNESS_H__ */