diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3dda9f0eda82..ee413332a9ae 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -328,6 +328,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 8271e50e3644..de512541628f 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; @@ -421,6 +422,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 c846ef4acf5b..8a9eae55b362 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -39,6 +39,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" /* @@ -99,6 +100,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]) @@ -606,7 +608,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) struct intel_display *display = to_intel_display(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 @@ -638,6 +640,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; } /* @@ -667,5 +672,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..6959b34c621e --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_legacy_oled_brightness.c @@ -0,0 +1,446 @@ +/* + * Copyright © 2025 Chris Xiong + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#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) { + drm_dbg_kms(aux->drm_dev, "intel_dp_aux_legacy_write_sequence: %*phN", (int)length, value_seq); + for (size_t p = 0; p < length; ++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_parameterized(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; + + 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 (size_t p = 0; p < nparameters; ++p) { + int pos = va_arg(args, int); + 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; + int ret; + + ret = drm_dp_dpcd_readb(aux, 0x490, &v); + if (ret < 1) + drm_info(display->drm, "intel_dp_aux_legacy_handshake: read dpcd register 0x490 failed: %d", ret); + else { + if (v != 1) { + for (int retries = 0; retries < 20; ++retries) { + for (int p = 0; p < 11; ++p) { + ret = drm_dp_dpcd_writeb(aux, 0x490, (u8)handshake_str[p]); + 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, "intel_dp_aux_legacy_handshake: handshake failed"); + 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_legacy_panel_data *panel_data = &connector->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, "get_elvss_max_offset: write failed"); + return; + } + if (drm_dp_dpcd_readb(aux, 0x493, &panel_data->elvss_max_offset) < 1) { + drm_err(display->drm, "get_elvss_max_offset: read failed"); + return; + } + drm_dbg_kms(display->drm, "elvss_max_offset: %d", (int)panel_data->elvss_max_offset); + } else + drm_err(display->drm, "get_elvss_max_offset: handshake failed"); +} + +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_legacy_panel_data *panel_data = &connector->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}; + + if (!intel_dp_aux_legacy_handshake(connector)) { + drm_err(display->drm, "get_tcon_gamma: handshake failed"); + return false; + } + if (!intel_dp_aux_legacy_write_sequence(aux, address_seq1, value_seq1, 6)) { + drm_err(display->drm, "get_tcon_gamma: write failed"); + return false; + } + if (!interm) { + drm_err(display->drm, "get_tcon_gamma: could not get hold of intermediate data"); + return false; + } + for (u16 i = 0; i < 0x20; ++i) { + u16 k = i * 0xb; + for (u16 j = 0; j <= 0x20; ++j) { + intel_dp_aux_legacy_write_sequence_parameterized(aux, address_seq2, value_seq2, 8, 3, + 1, (j < 0xb ? 0x2 : (j < 0x16 ? 0x4 : 0x8)), + 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 (u16 i = 0; i < 0x20 ; ++i) { + for (u16 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_legacy_panel_data *panel_data = &connector->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}; + + if (!intel_dp_aux_legacy_handshake(connector)) { + drm_err(display->drm, "write_brightness: handshake failed"); + return; + } + drm_dbg_kms(display->drm, "write_brightness %3d", brightness); + + if (!intel_dp_aux_legacy_write_sequence_parameterized(aux, address_seq1, value_seq1, 7, 2, + 4, panel_data->aor_buf[brightness * 2], //LSB of AOR[brightness] + 6, panel_data->aor_buf[brightness * 2 + 1])) //MSB of AOR[brightness] + goto fail; + + if (!intel_dp_aux_legacy_write_sequence_parameterized(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) { + if (!intel_dp_aux_legacy_write_sequence_parameterized(aux, address_seq3, value_seq3, 7, 3, + 2, 0x90, + 4, panel_data->acl_cutoff_and_delta_buf[(brightness - panel_data->brightness_for_acl - 1) * 2], // LSB of ACLCutoffAndDelta[brightness - brightness_acl - 1] + 6, panel_data->acl_cutoff_and_delta_buf[(brightness - panel_data->brightness_for_acl - 1) * 2 + 1])) // MSB of ACLCutoffAndDelta[brightness - brightness_acl - 1] + goto fail; + } else { + if (!intel_dp_aux_legacy_write_sequence_parameterized(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, 32, brightness_gamma); + write_addr_buf = kmalloc_array(0x21 * 2, 4, GFP_KERNEL); + write_val_buf = kmalloc_array(0x21 * 2, 1, GFP_KERNEL); + for (int 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 (drm_dp_dpcd_writeb(aux, 0x492, i + 0x10) < 1) goto fail; + 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_parameterized(aux, address_seq5, value_seq5, 14, 1, + 9, panel_data->SP[brightness])) + goto fail; + for (int 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: + if (write_addr_buf) + kfree(write_addr_buf); + if (write_val_buf) + kfree(write_val_buf); + drm_err(display->drm, "write_brightness: failed to write dpcd registers"); +} + +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_legacy_panel_data *panel_data = &connector->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; + for (int i = 0; i <= 0x20; ++i) { + old_d = 0xff; + for (int 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 (int i = 0; i < 101; ++i) { + for (int 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 (int i = 0; i < 101; ++i) { + drm_dbg_kms(display->drm, "interpolated gamma %3d %*phN", i, 33, panel_data->interpolated_gamma[i]); + } +} + +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_legacy_panel_data *panel_data = &connector->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; + u16 len; + + ret = request_firmware(&fw, "intel_legacy_panel_data.bin", dev); + if (ret < 0) + return ret; + ret = 0; + pdata = fw->data; + +#define load_array(arr, maxlen) \ + if (fw->size - (pdata - fw->data) < 2) goto fail_invalid_data; \ + memcpy(&len, pdata, 2); \ + pdata += 2; \ + len = __le16_to_cpu(len); \ + if (len > maxlen) goto fail_invalid_data; \ + if (fw->size - (pdata - fw->data) < len) goto fail_invalid_data; \ + memcpy(arr, pdata, len); \ + pdata += len; + + load_array(panel_data->aor_buf, 202); + load_array(panel_data->delvss, 101); + + if (fw->size - (pdata - fw->data) < 2) goto fail_invalid_data; + memcpy(&panel_data->brightness_for_acl, pdata, 2); + pdata += 2; + panel_data->brightness_for_acl = __le16_to_cpu(panel_data->brightness_for_acl); + + load_array(panel_data->acl_cutoff_and_delta_buf, 200); + load_array(panel_data->IRC, 909); + load_array(panel_data->SP, 101); + load_array(interm->interpolation, 505); + + 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 = &connector->panel.backlight.edp.legacy.panel_data; + int ret; + + panel_data->intermediates = kzalloc(sizeof(struct intel_legacy_panel_data_intermediate), GFP_KERNEL); + 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_legacy_panel_data *panel_data = &connector->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..785509e608c8 --- /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__ */