From patchwork Fri Oct 11 15:28:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Ma X-Patchwork-Id: 1175281 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46qX0m2tJJz9sP6; Sat, 12 Oct 2019 02:28:40 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1iIwqK-0002r3-20; Fri, 11 Oct 2019 15:28:36 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1iIwqF-0002qD-Pl for kernel-team@lists.ubuntu.com; Fri, 11 Oct 2019 15:28:31 +0000 Received: from [114.245.47.25] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1iIwqF-0004iz-1m for kernel-team@lists.ubuntu.com; Fri, 11 Oct 2019 15:28:31 +0000 From: Aaron Ma To: kernel-team@lists.ubuntu.com Subject: [PATCH 2/2] UBUNTU: SAUCE: drm/i915: customize DPCD brightness control for specific panel Date: Fri, 11 Oct 2019 23:28:22 +0800 Message-Id: <20191011152822.26495-3-aaron.ma@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191011152822.26495-1-aaron.ma@canonical.com> References: <20191011152822.26495-1-aaron.ma@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Lee Shawn C BugLink: https://bugs.launchpad.net/bugs/1844798 This panel (manufacturer is SDC, product ID is 0x4141) used manufacturer defined DPCD register to control brightness that not defined in eDP spec so far. This change follow panel vendor's instruction to support brightness adjustment. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97883 V2: To check sink OUI instead of EDID quirk. According to TCON's capability to decide to enable this method for brightness control. Cc: Jani Nikula Cc: Adam Jackson Cc: Maarten Lankhorst Cc: Gustavo Padovan Cc: Cooper Chiou Signed-off-by: Lee Shawn C Link: https://patchwork.kernel.org/patch/11180697/ Signed-off-by: Aaron Ma --- drivers/gpu/drm/drm_dp_helper.c | 18 ++- drivers/gpu/drm/i915/intel_dp.c | 7 + drivers/gpu/drm/i915/intel_dp_aux_backlight.c | 138 +++++++++++++++++- include/drm/drm_dp_helper.h | 20 +++ 4 files changed, 176 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 038bd1e3889a..64a95d147abf 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1225,6 +1225,8 @@ struct dpcd_quirk { static const struct dpcd_quirk dpcd_quirk_list[] = { /* Analogix 7737 needs reduced M and N at HBR2 link rates */ { OUI(0x00, 0x22, 0xb9), true, BIT(DP_DPCD_QUIRK_LIMITED_M_N) }, + /* Samsung eDP panel */ + { OUI(0xba, 0x41, 0x59), false, BIT(DP_DPCD_QUIRK_CUSTOMIZE_BRIGHTNESS_CONTROL) }, }; #undef OUI @@ -1238,7 +1240,7 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { * to device identification string and hardware/firmware revisions later. */ static u32 -drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch) +drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch, u8 *tcon_cap) { const struct dpcd_quirk *quirk; u32 quirks = 0; @@ -1253,6 +1255,11 @@ drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch) if (memcmp(quirk->oui, ident->oui, sizeof(ident->oui)) != 0) continue; + if (quirk->quirks == DP_DPCD_QUIRK_CUSTOMIZE_BRIGHTNESS_CONTROL && + (!(tcon_cap[1] & DP_BRIGHTNESS_CONTROL_NITS) || + !(tcon_cap[2] & DP_BRIGHTNESS_CONTROL_BY_AUX))) + continue; + quirks |= quirk->quirks; } @@ -1276,12 +1283,19 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, struct drm_dp_dpcd_ident *ident = &desc->ident; unsigned int offset = is_branch ? DP_BRANCH_OUI : DP_SINK_OUI; int ret, dev_id_len; + u8 tcon_cap[4] = {0}; ret = drm_dp_dpcd_read(aux, offset, ident, sizeof(*ident)); if (ret < 0) return ret; - desc->quirks = drm_dp_get_quirks(ident, is_branch); + if (offset == DP_SINK_OUI) { + ret = drm_dp_dpcd_read(aux, DP_EDP_TCON_CAPABILITY_BYTE0, tcon_cap, sizeof(tcon_cap)); + if (ret < 0) + return ret; + } + + desc->quirks = drm_dp_get_quirks(ident, is_branch, tcon_cap); dev_id_len = strnlen(ident->device_id, sizeof(ident->device_id)); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6753b73ebc4e..0cdf4a65e91f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5934,6 +5934,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, goto out_vdd_off; } + if (drm_dp_has_quirk(&intel_dp->desc, + DP_DPCD_QUIRK_CUSTOMIZE_BRIGHTNESS_CONTROL)) { + i915_modparams.enable_dpcd_backlight = true; + i915_modparams.fastboot = false; + DRM_DEBUG_KMS("Using specific DPCD to control brightness\n"); + } + mutex_lock(&dev->mode_config.mutex); edid = drm_get_edid(connector, &intel_dp->aux.ddc); if (edid) { diff --git a/drivers/gpu/drm/i915/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/intel_dp_aux_backlight.c index cbf61ac2910d..bde2720f2f8a 100644 --- a/drivers/gpu/drm/i915/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/intel_dp_aux_backlight.c @@ -24,6 +24,111 @@ #include "intel_drv.h" +#define EDP_CUSTOMIZE_MAX_BRIGHTNESS_LEVEL (512) + +static uint32_t intel_dp_aux_get_customize_backlight(struct intel_connector *connector) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); + uint8_t read_val[2] = { 0x0 }; + + if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BRIGHTNESS_NITS, + &read_val, sizeof(read_val)) < 0) { + DRM_DEBUG_KMS("Failed to read DPCD register %x\n", + DP_EDP_BRIGHTNESS_NITS); + return 0; + } + + return (read_val[1] << 8 | read_val[0]); +} + +static void +intel_dp_aux_set_customize_backlight(const struct drm_connector_state *conn_state, u32 level) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); + struct intel_panel *panel = &connector->panel; + uint8_t new_vals[4]; + + if (level > panel->backlight.max) + level = panel->backlight.max; + + new_vals[0] = level & 0xFF; + new_vals[1] = (level & 0xFF00) >> 8; + new_vals[2] = 0; + new_vals[3] = 0; + + if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_BRIGHTNESS_NITS, new_vals, 4) < 0) + DRM_DEBUG_KMS("Failed to write aux backlight level\n"); +} + +static void intel_dp_aux_enable_customize_backlight(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); + uint8_t read_val[4], i; + uint8_t write_val[8] = {0x00, 0x00, 0xF0, 0x01, 0x90, 0x01, 0x00, 0x00}; + + if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_LUMINANCE_OVERRIDE, write_val, sizeof(write_val)) < 0) + DRM_DEBUG_KMS("Failed to write panel luminance.\n"); + + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BRIGHTNESS_OPTIMIZATION, 0x01) < 0) + DRM_DEBUG_KMS("Failed to write %x\n", + DP_EDP_BRIGHTNESS_OPTIMIZATION); + /* write source OUI */ + write_val[0] = 0x00; + write_val[1] = 0xaa; + write_val[2] = 0x01; + if (drm_dp_dpcd_write(&intel_dp->aux, DP_SOURCE_OUI, write_val, 3) < 0) + DRM_DEBUG_KMS("Failed to write OUI\n"); + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_GETSET_CTRL_PARAMS, read_val) != 1) + DRM_DEBUG_KMS("Failed to read %x\n", + DP_EDP_GETSET_CTRL_PARAMS); + + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_GETSET_CTRL_PARAMS, 0) != 1) + DRM_DEBUG_KMS("Failed to write %x\n", + DP_EDP_GETSET_CTRL_PARAMS); + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_GETSET_CTRL_PARAMS, read_val) != 1) + DRM_DEBUG_KMS("Failed to read %x\n", + DP_EDP_GETSET_CTRL_PARAMS); + + if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_CONTENT_LUMINANCE, &read_val, sizeof(read_val)) < 0) + DRM_DEBUG_KMS("Failed to read %x\n", + DP_EDP_CONTENT_LUMINANCE); + + memset(read_val, 0x0, 4); + if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_CONTENT_LUMINANCE, read_val, sizeof(read_val)) < 0) + DRM_DEBUG_KMS("Failed to write %x\n", + DP_EDP_CONTENT_LUMINANCE); + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_GETSET_CTRL_PARAMS, read_val) != 1) + DRM_DEBUG_KMS("Failed to read %x\n", + DP_EDP_GETSET_CTRL_PARAMS); + + if (drm_dp_dpcd_read(&intel_dp->aux, DP_SOURCE_OUI, read_val, 4) < 0) + DRM_DEBUG_KMS("Failed to read OUI\n"); + + DRM_DEBUG_KMS("got OUI %3ph\n", read_val); + + for (i = 0; i < 6; i++) { + intel_dp_aux_set_customize_backlight(conn_state, connector->panel.backlight.level); + + msleep(60); + if (intel_dp_aux_get_customize_backlight(connector)) + return; + } + + DRM_DEBUG_KMS("Restore brightness may have problem.\n"); +} + +static void intel_dp_aux_disable_customize_backlight(const struct drm_connector_state *old_conn_state) +{ + // do nothing + return; +} + static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) { uint8_t reg_val = 0; @@ -197,6 +302,19 @@ static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old set_aux_backlight_enable(enc_to_intel_dp(old_conn_state->best_encoder), false); } +static int intel_dp_aux_setup_customize_backlight(struct intel_connector *connector, + enum pipe pipe) +{ + struct intel_panel *panel = &connector->panel; + + panel->backlight.max = EDP_CUSTOMIZE_MAX_BRIGHTNESS_LEVEL; + panel->backlight.min = 0; + panel->backlight.level = panel->backlight.get(connector); + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; +} + static u32 intel_dp_aux_calc_max_backlight(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ -308,6 +426,7 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector) int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector) { struct intel_panel *panel = &intel_connector->panel; + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_connector->encoder->base); if (!i915_modparams.enable_dpcd_backlight) return -ENODEV; @@ -315,11 +434,20 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector) if (!intel_dp_aux_display_control_capable(intel_connector)) return -ENODEV; - panel->backlight.setup = intel_dp_aux_setup_backlight; - panel->backlight.enable = intel_dp_aux_enable_backlight; - panel->backlight.disable = intel_dp_aux_disable_backlight; - panel->backlight.set = intel_dp_aux_set_backlight; - panel->backlight.get = intel_dp_aux_get_backlight; + if (drm_dp_has_quirk(&intel_dp->desc, + DP_DPCD_QUIRK_CUSTOMIZE_BRIGHTNESS_CONTROL)) { + panel->backlight.setup = intel_dp_aux_setup_customize_backlight; + panel->backlight.enable = intel_dp_aux_enable_customize_backlight; + panel->backlight.disable = intel_dp_aux_disable_customize_backlight; + panel->backlight.set = intel_dp_aux_set_customize_backlight; + panel->backlight.get = intel_dp_aux_get_customize_backlight; + } else { + panel->backlight.setup = intel_dp_aux_setup_backlight; + panel->backlight.enable = intel_dp_aux_enable_backlight; + panel->backlight.disable = intel_dp_aux_disable_backlight; + panel->backlight.set = intel_dp_aux_set_backlight; + panel->backlight.get = intel_dp_aux_get_backlight; + } return 0; } diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 836252de56a2..6f08017e695b 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -625,6 +625,20 @@ /* up to ID_SLOT_63 at 0x2ff */ #define DP_SOURCE_OUI 0x300 +#define DP_EDP_TCON_CAPABILITY_BYTE0 0x340 + +#define DP_EDP_TCON_CAPABILITY_BYTE1 0x341 +#define DP_BRIGHTNESS_CONTROL_NITS 0x10 + +#define DP_EDP_TCON_CAPABILITY_BYTE2 0x342 +#define DP_BRIGHTNESS_CONTROL_BY_AUX 0x01 + +#define DP_EDP_GETSET_CTRL_PARAMS 0x344 +#define DP_EDP_CONTENT_LUMINANCE 0x346 +#define DP_EDP_PANEL_LUMINANCE_OVERRIDE 0x34A +#define DP_EDP_BRIGHTNESS_NITS 0x354 +#define DP_EDP_BRIGHTNESS_OPTIMIZATION 0x358 + #define DP_SINK_OUI 0x400 #define DP_BRANCH_OUI 0x500 #define DP_BRANCH_ID 0x503 @@ -1161,6 +1175,12 @@ enum drm_dp_quirk { * to 16 bits. */ DP_DPCD_QUIRK_LIMITED_M_N, + /** + * @DP_DPCD_QUIRK_NON_STANDARD_BRIGHTNESS_CONTROL: + * + * The device used specific DPCD register to control brightness. + */ + DP_DPCD_QUIRK_CUSTOMIZE_BRIGHTNESS_CONTROL, }; /**