V2: Addressed review comments from Ville:
- Do not track scrambling status in DRM layer, track somewhere in
driver like in intel_crtc_state.
- Don't talk to monitor at such a low layer, set monitor scrambling
in intel_enable_ddi() before enabling the port.
Signed-off-by: Shashank Sharma <shashank.sharma@xxxxxxxxx>
---
drivers/gpu/drm/i915/i915_reg.h | 2 ++
drivers/gpu/drm/i915/intel_ddi.c | 26 +++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 11 ++++++
drivers/gpu/drm/i915/intel_hdmi.c | 70 +++++++++++++++++++++++++++++++++++++++
4 files changed, 109 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 495b789..cc85892 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7807,6 +7807,8 @@ enum {
#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12)
#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8)
#define TRANS_DDI_BFI_ENABLE (1<<4)
+#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1<<4)
+#define TRANS_DDI_HDMI_SCRAMBLING (1<<0)
/* DisplayPort Transport Control */
#define _DP_TP_CTL_A 0x64040
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 9a9a670..cc7e091 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1278,6 +1278,11 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
temp |= TRANS_DDI_MODE_SELECT_HDMI;
else
temp |= TRANS_DDI_MODE_SELECT_DVI;
+
+ if (IS_GEMINILAKE(dev_priv))
+ temp = intel_hdmi_handle_source_scrambling(
+ intel_encoder,
+ &intel_crtc->config->base.adjusted_mode, temp);
} else if (type == INTEL_OUTPUT_ANALOG) {
temp |= TRANS_DDI_MODE_SELECT_FDI;
temp |= (intel_crtc->config->fdi_lanes - 1) << 1;
@@ -1845,6 +1850,21 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder,
struct intel_digital_port *intel_dig_port =
enc_to_dig_port(encoder);
+ if (IS_GEMINILAKE(dev_priv)) {
+ /*
+ * GLK sports a native HDMI 2.0 controller. If required
+ * clock rate is > 340 Mhz && scrambling is supported
+ * by monitor, enable scrambling before enabling the
+ * HDMI 2.0 port. The sink can choose to disable the
+ * scrambling if it doesn't detect a scrambled within
+ * 100 ms.
+ */
+ intel_hdmi_handle_monitor_scrambling(intel_encoder,
+ conn_state->connector,
+ intel_crtc->config,
+ true);
+ }
+
/* In HDMI/DVI mode, the port width, and swing/emphasis values
* are ignored so nothing special needs to be done besides
* enabling the port.
@@ -1885,6 +1905,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder,
intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
}
+ if (type == INTEL_OUTPUT_HDMI) {
+ intel_hdmi_handle_monitor_scrambling(intel_encoder,
+ old_conn_state->connector,
+ intel_crtc->config, false);
+ }
+
if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 393f243..300353c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -681,6 +681,9 @@ struct intel_crtc_state {
/* Gamma mode programmed on the pipe */
uint32_t gamma_mode;
+
+ /* HDMI scrambling status (monitor) */
+ bool scrambling;
};
struct vlv_wm_state {
@@ -1588,6 +1591,14 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state);
+uint32_t
+intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder,
+ struct drm_display_mode *mode,
+ uint32_t config);
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
+ struct intel_crtc_state *config,
+ bool enable);
void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index ebae2bd..41d3309 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -34,6 +34,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
+#include <drm/drm_scdc_helper.h>
#include "intel_drv.h"
#include <drm/i915_drm.h>
#include <drm/intel_lpe_audio.h>
@@ -1795,6 +1796,75 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
}
+void intel_hdmi_handle_monitor_scrambling(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
+ struct intel_crtc_state *config,
+ bool enable)
+{
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
+ struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
+ struct drm_scrambling *scrambling = &scdc->scrambling;
+ struct drm_display_mode *mode = &config->base.adjusted_mode;
+ struct drm_i915_private *dev_priv = connector->dev->dev_private;
+ struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv,
+ intel_hdmi->ddc_bus);
+
+ if (!scrambling->supported)
+ return;
+
+ DRM_DEBUG_KMS("Setting monitor scrambling for enc:%s connector:%s\n",
+ intel_encoder->base.name, connector->name);
+
+ /* Enable monitor scrambling */
+ if (enable) {
+ if (mode->clock > 340000 || scrambling->low_rates) {
+ config->scrambling = drm_scdc_enable_scrambling(adptr);
+ if (!config->scrambling)
+ DRM_ERROR("Can't enable monitor scrambling\n");
+ }
+ return;
+ }
+
+ /* Disable monitor scrambling */
+ if (config->scrambling) {
+ config->scrambling = !(drm_scdc_disable_scrambling(adptr));
+ if (config->scrambling)
+ DRM_ERROR("Can't disable monitor scrambling\n");
+ }
+
+}
+
+uint32_t
+intel_hdmi_handle_source_scrambling(struct intel_encoder *intel_encoder,
+ struct drm_display_mode *mode, uint32_t hdmi_config)
+{
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
+ struct drm_connector *connector = &intel_hdmi->attached_connector->base;
+ struct drm_hdmi_info *hdmi_info = &connector->display_info.hdmi;
+ struct drm_scrambling *scrambling = &hdmi_info->scdc.scrambling;
+
+ DRM_DEBUG_KMS("Setting scrambling for enc:%s connector:%s\n",
+ intel_encoder->base.name, connector->name);
+
+ hdmi_config &= ~TRANS_DDI_HDMI_SCRAMBLING;
+ hdmi_config &= ~TRANS_DDI_HIGH_TMDS_CHAR_RATE;
+
+ if (mode->clock <= 340000) {
+ /* Few sinks support scrambling at rate < 340 MHz too */
+ if (scrambling->low_rates)
+ hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING;
+ return hdmi_config;
+ }
+
+ /* Scrambling or not, if clock > 340 MHz, set high char rate */
+ hdmi_config |= TRANS_DDI_HIGH_TMDS_CHAR_RATE;
+
+ if (scrambling->supported)
+ hdmi_config |= TRANS_DDI_HDMI_SCRAMBLING;
+
+ return hdmi_config;
+}
+
static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
enum port port)
{