Commit 15953637 authored by Shashank Sharma's avatar Shashank Sharma Committed by Jani Nikula

drm/i915: enable scrambling

Geminilake platform sports a native HDMI 2.0 controller, and is
capable of driving pixel-clocks upto 594Mhz. HDMI 2.0 spec
mendates scrambling for these higher clocks, for reduced RF footprint.

This patch checks if the monitor supports scrambling, and if required,
enables it during the modeset.

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.

V3: Addressed review comments from Jani
 - In comments, function names, use "sink" instead of "monitor",
   so that the implementation could be close to the language of
   HDMI spec.

V4: Addressed review comment from Maarten
 - scrambling -> hdmi_scrambling
 - high_tmds_clock_ratio -> hdmi_high_tmds_clock_ratio

V5: Addressed review comments from Ville and Ander
 - Do not modifiy the crtc_state after compute_config. Move all
   scrambling and tmds_clock_ratio calcutations to compute_config.
 - While setting scrambling for source/sink, do not check the
   conditions again, just go by the crtc_state flags. This will
   simplyfy the condition checks.

V6: Addressed review comments from Ville
 - Do not add IS_GLK check in disable/enable function, instead add it
   in compute_config, while setting state flags.
 - Remove unnecessary paranthesis.
 - Simplyfy handle_sink_scrambling function as suggested.
 - Add readout code for scrambling status in get_ddi_config and add a
   check for the same in pipe_config_compare.

V7: Addressed review comments from Ander/Ville
 - No separate function for source scrambling, make it inline
 - Align the last line of the macro TRANS_DDI_HDMI_SCRAMBLING_MASK
 - Do not add platform check while setting source scrambling
 - Use pipe_config instead of crtc->config to set sink scrambling
 - To readout scrambling status, Compare with SCRAMBLING_MASK
   not any of its bits
 - Remove platform check in intel_pipe_config_compare while checking
   scrambling status

V8: Fixed mege conflict, Addressed review comments from Ander
 - Remove the desciption/comment about scrambling fom the caller, move
   it to the function
 - Move the IS_GLK check into scrambling function
 - Fix alignment

V9: Fixed review comments from Ville, Ander
 - Pass the scrambling state variables as bool input to the sink_scrambling
   function and let the disable call be unconditional.
 - Fix alignments in function calls and debug messages.
 - Add kernel doc for function intel_hdmi_handle_sink_scrambling

V10: Rebase
Signed-off-by: default avatarShashank Sharma <shashank.sharma@intel.com>
Reviewed-by: default avatarAnder Conselvan de Oliveira <conselvan2@gmail.com>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1489404244-16608-6-git-send-email-shashank.sharma@intel.com
parent 44a126ba
...@@ -7829,7 +7829,14 @@ enum { ...@@ -7829,7 +7829,14 @@ enum {
#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12) #define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12)
#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) #define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12)
#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8) #define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8)
#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1<<7)
#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1<<6)
#define TRANS_DDI_BFI_ENABLE (1<<4) #define TRANS_DDI_BFI_ENABLE (1<<4)
#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1<<4)
#define TRANS_DDI_HDMI_SCRAMBLING (1<<0)
#define TRANS_DDI_HDMI_SCRAMBLING_MASK (TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE \
| TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ \
| TRANS_DDI_HDMI_SCRAMBLING)
/* DisplayPort Transport Control */ /* DisplayPort Transport Control */
#define _DP_TP_CTL_A 0x64040 #define _DP_TP_CTL_A 0x64040
......
...@@ -1244,6 +1244,11 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state) ...@@ -1244,6 +1244,11 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state)
temp |= TRANS_DDI_MODE_SELECT_HDMI; temp |= TRANS_DDI_MODE_SELECT_HDMI;
else else
temp |= TRANS_DDI_MODE_SELECT_DVI; temp |= TRANS_DDI_MODE_SELECT_DVI;
if (crtc_state->hdmi_scrambling)
temp |= TRANS_DDI_HDMI_SCRAMBLING_MASK;
if (crtc_state->hdmi_high_tmds_clock_ratio)
temp |= TRANS_DDI_HIGH_TMDS_CHAR_RATE;
} else if (type == INTEL_OUTPUT_ANALOG) { } else if (type == INTEL_OUTPUT_ANALOG) {
temp |= TRANS_DDI_MODE_SELECT_FDI; temp |= TRANS_DDI_MODE_SELECT_FDI;
temp |= (crtc_state->fdi_lanes - 1) << 1; temp |= (crtc_state->fdi_lanes - 1) << 1;
...@@ -1816,6 +1821,12 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder, ...@@ -1816,6 +1821,12 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder,
if (type == INTEL_OUTPUT_HDMI) { if (type == INTEL_OUTPUT_HDMI) {
struct intel_digital_port *intel_dig_port = struct intel_digital_port *intel_dig_port =
enc_to_dig_port(encoder); enc_to_dig_port(encoder);
bool clock_ratio = pipe_config->hdmi_high_tmds_clock_ratio;
bool scrambling = pipe_config->hdmi_scrambling;
intel_hdmi_handle_sink_scrambling(intel_encoder,
conn_state->connector,
clock_ratio, scrambling);
/* In HDMI/DVI mode, the port width, and swing/emphasis values /* In HDMI/DVI mode, the port width, and swing/emphasis values
* are ignored so nothing special needs to be done besides * are ignored so nothing special needs to be done besides
...@@ -1849,6 +1860,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder, ...@@ -1849,6 +1860,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder,
if (old_crtc_state->has_audio) if (old_crtc_state->has_audio)
intel_audio_codec_disable(intel_encoder); intel_audio_codec_disable(intel_encoder);
if (type == INTEL_OUTPUT_HDMI) {
intel_hdmi_handle_sink_scrambling(intel_encoder,
old_conn_state->connector,
false, false);
}
if (type == INTEL_OUTPUT_EDP) { if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
...@@ -1975,6 +1992,12 @@ void intel_ddi_get_config(struct intel_encoder *encoder, ...@@ -1975,6 +1992,12 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
if (intel_hdmi->infoframe_enabled(&encoder->base, pipe_config)) if (intel_hdmi->infoframe_enabled(&encoder->base, pipe_config))
pipe_config->has_infoframe = true; pipe_config->has_infoframe = true;
if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
TRANS_DDI_HDMI_SCRAMBLING_MASK)
pipe_config->hdmi_scrambling = true;
if (temp & TRANS_DDI_HIGH_TMDS_CHAR_RATE)
pipe_config->hdmi_high_tmds_clock_ratio = true;
/* fall through */ /* fall through */
case TRANS_DDI_MODE_SELECT_DVI: case TRANS_DDI_MODE_SELECT_DVI:
pipe_config->lane_count = 4; pipe_config->lane_count = 4;
......
...@@ -11710,6 +11710,9 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv, ...@@ -11710,6 +11710,9 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) || if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
PIPE_CONF_CHECK_I(limited_color_range); PIPE_CONF_CHECK_I(limited_color_range);
PIPE_CONF_CHECK_I(hdmi_scrambling);
PIPE_CONF_CHECK_I(hdmi_high_tmds_clock_ratio);
PIPE_CONF_CHECK_I(has_infoframe); PIPE_CONF_CHECK_I(has_infoframe);
PIPE_CONF_CHECK_I(has_audio); PIPE_CONF_CHECK_I(has_audio);
......
...@@ -732,6 +732,12 @@ struct intel_crtc_state { ...@@ -732,6 +732,12 @@ struct intel_crtc_state {
/* bitmask of visible planes (enum plane_id) */ /* bitmask of visible planes (enum plane_id) */
u8 active_planes; u8 active_planes;
/* HDMI scrambling status */
bool hdmi_scrambling;
/* HDMI High TMDS char rate ratio */
bool hdmi_high_tmds_clock_ratio;
}; };
struct intel_crtc { struct intel_crtc {
...@@ -1623,6 +1629,10 @@ struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); ...@@ -1623,6 +1629,10 @@ struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
bool intel_hdmi_compute_config(struct intel_encoder *encoder, bool intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config, struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state); struct drm_connector_state *conn_state);
void intel_hdmi_handle_sink_scrambling(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
bool high_tmds_clock_ratio,
bool scrambling);
void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable); void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_scdc_helper.h>
#include "intel_drv.h" #include "intel_drv.h"
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
#include <drm/intel_lpe_audio.h> #include <drm/intel_lpe_audio.h>
...@@ -1334,6 +1335,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1334,6 +1335,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct drm_scdc *scdc = &conn_state->connector->display_info.hdmi.scdc;
int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock; int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
int clock_12bpc = clock_8bpc * 3 / 2; int clock_12bpc = clock_8bpc * 3 / 2;
int desired_bpp; int desired_bpp;
...@@ -1403,6 +1405,16 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1403,6 +1405,16 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
pipe_config->lane_count = 4; pipe_config->lane_count = 4;
if (scdc->scrambling.supported && IS_GEMINILAKE(dev_priv)) {
if (scdc->scrambling.low_rates)
pipe_config->hdmi_scrambling = true;
if (pipe_config->port_clock > 340000) {
pipe_config->hdmi_scrambling = true;
pipe_config->hdmi_high_tmds_clock_ratio = true;
}
}
return true; return true;
} }
...@@ -1812,6 +1824,57 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c ...@@ -1812,6 +1824,57 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
} }
/*
* intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup
* @encoder: intel_encoder
* @connector: drm_connector
* @high_tmds_clock_ratio = bool to indicate if the function needs to set
* or reset the high tmds clock ratio for scrambling
* @scrambling: bool to Indicate if the function needs to set or reset
* sink scrambling
*
* This function handles scrambling on HDMI 2.0 capable sinks.
* If required clock rate is > 340 Mhz && scrambling is supported by sink
* it enables scrambling. This should be called before enabling the HDMI
* 2.0 port, as the sink can choose to disable the scrambling if it doesn't
* detect a scrambled clock within 100 ms.
*/
void intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
struct drm_connector *connector,
bool high_tmds_clock_ratio,
bool scrambling)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct drm_scrambling *sink_scrambling =
&connector->display_info.hdmi.scdc.scrambling;
struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus);
bool ret;
if (!sink_scrambling->supported)
return;
DRM_DEBUG_KMS("Setting sink scrambling for enc:%s connector:%s\n",
encoder->base.name, connector->name);
/* Set TMDS bit clock ratio to 1/40 or 1/10 */
ret = drm_scdc_set_high_tmds_clock_ratio(adptr, high_tmds_clock_ratio);
if (!ret) {
DRM_ERROR("Set TMDS ratio failed\n");
return;
}
/* Enable/disable sink scrambling */
ret = drm_scdc_set_scrambling(adptr, scrambling);
if (!ret) {
DRM_ERROR("Set sink scrambling failed\n");
return;
}
DRM_DEBUG_KMS("sink scrambling handled\n");
}
static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv, static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
enum port port) enum port port)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment