summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c186
1 files changed, 144 insertions, 42 deletions
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 33f72db99b58..8173de8aec63 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
@@ -34,8 +34,11 @@
* for some reason.
*/
-#include "i915_drv.h"
+#include <drm/drm_print.h>
+
+#include "i915_utils.h"
#include "intel_backlight.h"
+#include "intel_display_core.h"
#include "intel_display_types.h"
#include "intel_dp.h"
#include "intel_dp_aux_backlight.h"
@@ -450,9 +453,54 @@ intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pi
/* VESA backlight callbacks */
static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused)
{
+ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ struct intel_panel *panel = &connector->panel;
+ u8 buf[3];
+ u32 val = 0;
+ int ret;
+
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ ret = drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, buf,
+ sizeof(buf));
+ if (ret < 0) {
+ drm_err(intel_dp->aux.drm_dev,
+ "[CONNECTOR:%d:%s] Failed to read Luminance from DPCD\n",
+ connector->base.base.id, connector->base.name);
+ return 0;
+ }
+
+ val |= buf[0] | buf[1] << 8 | buf[2] << 16;
+ return val / 1000;
+ }
+
return connector->panel.backlight.level;
}
+static int
+intel_dp_aux_vesa_set_luminance(struct intel_connector *connector, u32 level)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ u8 buf[3];
+ int ret;
+
+ level = level * 1000;
+ level &= 0xffffff;
+ buf[0] = (level & 0x0000ff);
+ buf[1] = (level & 0x00ff00) >> 8;
+ buf[2] = (level & 0xff0000) >> 16;
+
+ ret = drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE,
+ buf, sizeof(buf));
+ if (ret != sizeof(buf)) {
+ drm_err(intel_dp->aux.drm_dev,
+ "%s: Failed to set VESA Aux Luminance: %d\n",
+ intel_dp->aux.name, ret);
+ return -EINVAL;
+ } else {
+ return 0;
+ }
+}
+
static void
intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
@@ -460,6 +508,11 @@ intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u3
struct intel_panel *panel = &connector->panel;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ if (!intel_dp_aux_vesa_set_luminance(connector, level))
+ return;
+ }
+
if (!panel->backlight.edp.vesa.info.aux_set) {
const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
@@ -476,6 +529,18 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
struct intel_connector *connector = to_intel_connector(conn_state->connector);
struct intel_panel *panel = &connector->panel;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ int ret;
+
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER,
+ DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE);
+
+ if (ret == 1)
+ return;
+
+ if (!intel_dp_aux_vesa_set_luminance(connector, level))
+ return;
+ }
if (!panel->backlight.edp.vesa.info.aux_enable) {
u32 pwm_level;
@@ -499,6 +564,9 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state
struct intel_panel *panel = &connector->panel;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ if (panel->backlight.edp.vesa.luminance_control_support)
+ return;
+
drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info);
if (!panel->backlight.edp.vesa.info.aux_enable)
@@ -509,56 +577,75 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state
static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe)
{
struct intel_display *display = to_intel_display(connector);
+ struct drm_luminance_range_info *luminance_range =
+ &connector->base.display_info.luminance_range;
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_panel *panel = &connector->panel;
u16 current_level;
u8 current_mode;
int ret;
- ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
- panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
- &current_level, &current_mode);
- if (ret < 0)
- return ret;
-
- drm_dbg_kms(display->drm,
- "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n",
- connector->base.base.id, connector->base.name,
- dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable));
- drm_dbg_kms(display->drm,
- "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n",
- connector->base.base.id, connector->base.name,
- dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set));
-
- if (!panel->backlight.edp.vesa.info.aux_set || !panel->backlight.edp.vesa.info.aux_enable) {
- ret = panel->backlight.pwm_funcs->setup(connector, pipe);
- if (ret < 0) {
- drm_err(display->drm,
- "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n",
- connector->base.base.id, connector->base.name, ret);
- return ret;
- }
- }
-
- if (panel->backlight.edp.vesa.info.aux_set) {
- panel->backlight.max = panel->backlight.edp.vesa.info.max;
- panel->backlight.min = 0;
- if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
- panel->backlight.level = current_level;
- panel->backlight.enabled = panel->backlight.level != 0;
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ if (luminance_range->max_luminance) {
+ panel->backlight.max = luminance_range->max_luminance;
+ panel->backlight.min = luminance_range->min_luminance;
} else {
- panel->backlight.level = panel->backlight.max;
- panel->backlight.enabled = false;
+ panel->backlight.max = 512;
+ panel->backlight.min = 0;
}
+ panel->backlight.level = intel_dp_aux_vesa_get_backlight(connector, 0);
+ panel->backlight.enabled = panel->backlight.level != 0;
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n",
+ connector->base.base.id, connector->base.name);
} else {
- panel->backlight.max = panel->backlight.pwm_level_max;
- panel->backlight.min = panel->backlight.pwm_level_min;
- if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
- panel->backlight.level = panel->backlight.pwm_funcs->get(connector, pipe);
- panel->backlight.enabled = panel->backlight.pwm_enabled;
+ ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
+ panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
+ &current_level, &current_mode);
+ if (ret < 0)
+ return ret;
+
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n",
+ connector->base.base.id, connector->base.name,
+ dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable));
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n",
+ connector->base.base.id, connector->base.name,
+ dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set));
+
+ if (!panel->backlight.edp.vesa.info.aux_set ||
+ !panel->backlight.edp.vesa.info.aux_enable) {
+ ret = panel->backlight.pwm_funcs->setup(connector, pipe);
+ if (ret < 0) {
+ drm_err(display->drm,
+ "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n",
+ connector->base.base.id, connector->base.name, ret);
+ return ret;
+ }
+ }
+
+ if (panel->backlight.edp.vesa.info.aux_set) {
+ panel->backlight.max = panel->backlight.edp.vesa.info.max;
+ panel->backlight.min = 0;
+ if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
+ panel->backlight.level = current_level;
+ panel->backlight.enabled = panel->backlight.level != 0;
+ } else {
+ panel->backlight.level = panel->backlight.max;
+ panel->backlight.enabled = false;
+ }
} else {
- panel->backlight.level = panel->backlight.max;
- panel->backlight.enabled = false;
+ panel->backlight.max = panel->backlight.pwm_level_max;
+ panel->backlight.min = panel->backlight.pwm_level_min;
+ if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
+ panel->backlight.level =
+ panel->backlight.pwm_funcs->get(connector, pipe);
+ panel->backlight.enabled = panel->backlight.pwm_enabled;
+ } else {
+ panel->backlight.level = panel->backlight.max;
+ panel->backlight.enabled = false;
+ }
}
}
@@ -574,6 +661,15 @@ intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(connector);
struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct intel_panel *panel = &connector->panel;
+
+ if ((intel_dp->edp_dpcd[3] & DP_EDP_PANEL_LUMINANCE_CONTROL_CAPABLE)) {
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX Luminance Based Backlight Control Supported!\n",
+ connector->base.base.id, connector->base.name);
+ panel->backlight.edp.vesa.luminance_control_support = true;
+ return true;
+ }
if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) {
drm_dbg_kms(display->drm,
@@ -603,6 +699,7 @@ static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(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;
@@ -639,6 +736,10 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
break;
}
+ /* For eDP 1.5 and above we are supposed to use VESA interface for brightness control */
+ if (intel_dp->edp_dpcd[0] >= DP_EDP_15)
+ try_vesa_interface = true;
+
/*
* Since Intel has their own backlight control interface, the majority of machines out there
* using DPCD backlight controls with Intel GPUs will be using this interface as opposed to
@@ -652,7 +753,8 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
* backlight interface at all. This means that the only sensible way for us to detect both
* interfaces is to probe for Intel's first, and VESA's second.
*/
- if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) {
+ if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector) &&
+ intel_dp->edp_dpcd[0] <= DP_EDP_14b) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Using Intel proprietary eDP backlight controls\n",
connector->base.base.id, connector->base.name);
panel->backlight.funcs = &intel_dp_hdr_bl_funcs;