drm/i915/bxt: add dsi transcoders
The BXT display connections have DSI transcoders A and C that can be muxed to any pipe, not unlike the eDP transcoder. Add the notion of DSI transcoders. The "normal" transcoders A, B and C are not used with BXT DSI, so care must be taken to avoid accessing those registers with DSI transcoders in the hardware state readout, modeset, and generally everywhere. v2: addressing comments by Ville: - rename the dsi get config function to hsw_get_dsi_transcoder_state - rebase onto the higher level split of pipe/transcoder functions - use more has_dsi_encoder as we can now because of the above, with no need to look at the transcoder so much - rename IS_DSI_TRANSCODER to transcoder_is_dsi - use the above a bit more instead of comparing to < TRANSCODER_EDP Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/299740536b7941e31b2744f3ce34f7afe936a771.1458313400.git.jani.nikula@intel.com
This commit is contained in:
parent
cf30429e94
commit
4d1de97568
|
@ -127,6 +127,8 @@ enum transcoder {
|
||||||
TRANSCODER_B,
|
TRANSCODER_B,
|
||||||
TRANSCODER_C,
|
TRANSCODER_C,
|
||||||
TRANSCODER_EDP,
|
TRANSCODER_EDP,
|
||||||
|
TRANSCODER_DSI_A,
|
||||||
|
TRANSCODER_DSI_C,
|
||||||
I915_MAX_TRANSCODERS
|
I915_MAX_TRANSCODERS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,11 +143,20 @@ static inline const char *transcoder_name(enum transcoder transcoder)
|
||||||
return "C";
|
return "C";
|
||||||
case TRANSCODER_EDP:
|
case TRANSCODER_EDP:
|
||||||
return "EDP";
|
return "EDP";
|
||||||
|
case TRANSCODER_DSI_A:
|
||||||
|
return "DSI A";
|
||||||
|
case TRANSCODER_DSI_C:
|
||||||
|
return "DSI C";
|
||||||
default:
|
default:
|
||||||
return "<invalid>";
|
return "<invalid>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool transcoder_is_dsi(enum transcoder transcoder)
|
||||||
|
{
|
||||||
|
return transcoder == TRANSCODER_DSI_A || transcoder == TRANSCODER_DSI_C;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I915_MAX_PLANES in the enum below is the maximum (across all platforms)
|
* I915_MAX_PLANES in the enum below is the maximum (across all platforms)
|
||||||
* number of planes per CRTC. Not all platforms really have this many planes,
|
* number of planes per CRTC. Not all platforms really have this many planes,
|
||||||
|
@ -196,6 +207,8 @@ enum intel_display_power_domain {
|
||||||
POWER_DOMAIN_TRANSCODER_B,
|
POWER_DOMAIN_TRANSCODER_B,
|
||||||
POWER_DOMAIN_TRANSCODER_C,
|
POWER_DOMAIN_TRANSCODER_C,
|
||||||
POWER_DOMAIN_TRANSCODER_EDP,
|
POWER_DOMAIN_TRANSCODER_EDP,
|
||||||
|
POWER_DOMAIN_TRANSCODER_DSI_A,
|
||||||
|
POWER_DOMAIN_TRANSCODER_DSI_C,
|
||||||
POWER_DOMAIN_PORT_DDI_A_LANES,
|
POWER_DOMAIN_PORT_DDI_A_LANES,
|
||||||
POWER_DOMAIN_PORT_DDI_B_LANES,
|
POWER_DOMAIN_PORT_DDI_B_LANES,
|
||||||
POWER_DOMAIN_PORT_DDI_C_LANES,
|
POWER_DOMAIN_PORT_DDI_C_LANES,
|
||||||
|
|
|
@ -1061,6 +1061,8 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
|
||||||
uint32_t temp;
|
uint32_t temp;
|
||||||
|
|
||||||
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
|
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
|
||||||
|
WARN_ON(transcoder_is_dsi(cpu_transcoder));
|
||||||
|
|
||||||
temp = TRANS_MSA_SYNC_CLK;
|
temp = TRANS_MSA_SYNC_CLK;
|
||||||
switch (intel_crtc->config->pipe_bpp) {
|
switch (intel_crtc->config->pipe_bpp) {
|
||||||
case 18:
|
case 18:
|
||||||
|
@ -1942,6 +1944,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
|
||||||
struct intel_hdmi *intel_hdmi;
|
struct intel_hdmi *intel_hdmi;
|
||||||
u32 temp, flags = 0;
|
u32 temp, flags = 0;
|
||||||
|
|
||||||
|
/* XXX: DSI transcoder paranoia */
|
||||||
|
if (WARN_ON(transcoder_is_dsi(cpu_transcoder)))
|
||||||
|
return;
|
||||||
|
|
||||||
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
||||||
if (temp & TRANS_DDI_PHSYNC)
|
if (temp & TRANS_DDI_PHSYNC)
|
||||||
flags |= DRM_MODE_FLAG_PHSYNC;
|
flags |= DRM_MODE_FLAG_PHSYNC;
|
||||||
|
|
|
@ -4900,6 +4900,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
|
||||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
struct intel_encoder *encoder;
|
struct intel_encoder *encoder;
|
||||||
int pipe = intel_crtc->pipe, hsw_workaround_pipe;
|
int pipe = intel_crtc->pipe, hsw_workaround_pipe;
|
||||||
|
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
|
||||||
struct intel_crtc_state *pipe_config =
|
struct intel_crtc_state *pipe_config =
|
||||||
to_intel_crtc_state(crtc->state);
|
to_intel_crtc_state(crtc->state);
|
||||||
|
|
||||||
|
@ -4916,11 +4917,14 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
|
||||||
if (intel_crtc->config->has_dp_encoder)
|
if (intel_crtc->config->has_dp_encoder)
|
||||||
intel_dp_set_m_n(intel_crtc, M1_N1);
|
intel_dp_set_m_n(intel_crtc, M1_N1);
|
||||||
|
|
||||||
|
if (!intel_crtc->config->has_dsi_encoder)
|
||||||
intel_set_pipe_timings(intel_crtc);
|
intel_set_pipe_timings(intel_crtc);
|
||||||
|
|
||||||
intel_set_pipe_src_size(intel_crtc);
|
intel_set_pipe_src_size(intel_crtc);
|
||||||
|
|
||||||
if (intel_crtc->config->cpu_transcoder != TRANSCODER_EDP) {
|
if (cpu_transcoder != TRANSCODER_EDP &&
|
||||||
I915_WRITE(PIPE_MULT(intel_crtc->config->cpu_transcoder),
|
!transcoder_is_dsi(cpu_transcoder)) {
|
||||||
|
I915_WRITE(PIPE_MULT(cpu_transcoder),
|
||||||
intel_crtc->config->pixel_multiplier - 1);
|
intel_crtc->config->pixel_multiplier - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4929,7 +4933,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
|
||||||
&intel_crtc->config->fdi_m_n, NULL);
|
&intel_crtc->config->fdi_m_n, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!intel_crtc->config->has_dsi_encoder)
|
||||||
haswell_set_pipeconf(crtc);
|
haswell_set_pipeconf(crtc);
|
||||||
|
|
||||||
haswell_set_pipe_gamma(crtc);
|
haswell_set_pipe_gamma(crtc);
|
||||||
haswell_set_pipemisc(crtc);
|
haswell_set_pipemisc(crtc);
|
||||||
|
|
||||||
|
@ -4972,6 +4978,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
|
||||||
dev_priv->display.initial_watermarks(pipe_config);
|
dev_priv->display.initial_watermarks(pipe_config);
|
||||||
else
|
else
|
||||||
intel_update_watermarks(crtc);
|
intel_update_watermarks(crtc);
|
||||||
|
|
||||||
|
/* XXX: Do the pipe assertions at the right place for BXT DSI. */
|
||||||
|
if (!intel_crtc->config->has_dsi_encoder)
|
||||||
intel_enable_pipe(intel_crtc);
|
intel_enable_pipe(intel_crtc);
|
||||||
|
|
||||||
if (intel_crtc->config->has_pch_encoder)
|
if (intel_crtc->config->has_pch_encoder)
|
||||||
|
@ -5105,6 +5114,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
|
||||||
drm_crtc_vblank_off(crtc);
|
drm_crtc_vblank_off(crtc);
|
||||||
assert_vblank_disabled(crtc);
|
assert_vblank_disabled(crtc);
|
||||||
|
|
||||||
|
/* XXX: Do the pipe assertions at the right place for BXT DSI. */
|
||||||
|
if (!intel_crtc->config->has_dsi_encoder)
|
||||||
intel_disable_pipe(intel_crtc);
|
intel_disable_pipe(intel_crtc);
|
||||||
|
|
||||||
if (intel_crtc->config->dp_encoder_is_mst)
|
if (intel_crtc->config->dp_encoder_is_mst)
|
||||||
|
@ -9957,6 +9968,47 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
|
||||||
return tmp & PIPECONF_ENABLE;
|
return tmp & PIPECONF_ENABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc,
|
||||||
|
struct intel_crtc_state *pipe_config,
|
||||||
|
unsigned long *power_domain_mask)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->base.dev;
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
enum intel_display_power_domain power_domain;
|
||||||
|
enum port port;
|
||||||
|
enum transcoder cpu_transcoder;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
pipe_config->has_dsi_encoder = false;
|
||||||
|
|
||||||
|
for_each_port_masked(port, BIT(PORT_A) | BIT(PORT_C)) {
|
||||||
|
if (port == PORT_A)
|
||||||
|
cpu_transcoder = TRANSCODER_DSI_A;
|
||||||
|
else
|
||||||
|
cpu_transcoder = TRANSCODER_DSI_C;
|
||||||
|
|
||||||
|
power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
|
||||||
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
||||||
|
continue;
|
||||||
|
*power_domain_mask |= BIT(power_domain);
|
||||||
|
|
||||||
|
/* XXX: this works for video mode only */
|
||||||
|
tmp = I915_READ(BXT_MIPI_PORT_CTRL(port));
|
||||||
|
if (!(tmp & DPI_ENABLE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tmp = I915_READ(MIPI_CTRL(port));
|
||||||
|
if ((tmp & BXT_PIPE_SELECT_MASK) != BXT_PIPE_SELECT(crtc->pipe))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pipe_config->cpu_transcoder = cpu_transcoder;
|
||||||
|
pipe_config->has_dsi_encoder = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipe_config->has_dsi_encoder;
|
||||||
|
}
|
||||||
|
|
||||||
static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
|
static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
|
||||||
struct intel_crtc_state *pipe_config)
|
struct intel_crtc_state *pipe_config)
|
||||||
{
|
{
|
||||||
|
@ -10018,12 +10070,22 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
|
||||||
|
|
||||||
active = hsw_get_transcoder_state(crtc, pipe_config, &power_domain_mask);
|
active = hsw_get_transcoder_state(crtc, pipe_config, &power_domain_mask);
|
||||||
|
|
||||||
|
if (IS_BROXTON(dev_priv)) {
|
||||||
|
bxt_get_dsi_transcoder_state(crtc, pipe_config,
|
||||||
|
&power_domain_mask);
|
||||||
|
WARN_ON(active && pipe_config->has_dsi_encoder);
|
||||||
|
if (pipe_config->has_dsi_encoder)
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!active)
|
if (!active)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!pipe_config->has_dsi_encoder) {
|
||||||
haswell_get_ddi_port_state(crtc, pipe_config);
|
haswell_get_ddi_port_state(crtc, pipe_config);
|
||||||
|
|
||||||
intel_get_pipe_timings(crtc, pipe_config);
|
intel_get_pipe_timings(crtc, pipe_config);
|
||||||
|
}
|
||||||
|
|
||||||
intel_get_pipe_src_size(crtc, pipe_config);
|
intel_get_pipe_src_size(crtc, pipe_config);
|
||||||
|
|
||||||
if (INTEL_INFO(dev)->gen >= 9) {
|
if (INTEL_INFO(dev)->gen >= 9) {
|
||||||
|
@ -10048,7 +10110,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
|
||||||
pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
|
pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
|
||||||
(I915_READ(IPS_CTL) & IPS_ENABLE);
|
(I915_READ(IPS_CTL) & IPS_ENABLE);
|
||||||
|
|
||||||
if (pipe_config->cpu_transcoder != TRANSCODER_EDP) {
|
if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
|
||||||
|
!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
|
||||||
pipe_config->pixel_multiplier =
|
pipe_config->pixel_multiplier =
|
||||||
I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1;
|
I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -15520,10 +15583,15 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->base.dev;
|
struct drm_device *dev = crtc->base.dev;
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder);
|
enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
|
||||||
|
|
||||||
/* Clear any frame start delays used for debugging left by the BIOS */
|
/* Clear any frame start delays used for debugging left by the BIOS */
|
||||||
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
|
if (!transcoder_is_dsi(cpu_transcoder)) {
|
||||||
|
i915_reg_t reg = PIPECONF(cpu_transcoder);
|
||||||
|
|
||||||
|
I915_WRITE(reg,
|
||||||
|
I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
/* restore vblank interrupts to correct state */
|
/* restore vblank interrupts to correct state */
|
||||||
drm_crtc_vblank_reset(&crtc->base);
|
drm_crtc_vblank_reset(&crtc->base);
|
||||||
|
@ -16194,6 +16262,7 @@ intel_display_capture_error_state(struct drm_device *dev)
|
||||||
error->pipe[i].stat = I915_READ(PIPESTAT(i));
|
error->pipe[i].stat = I915_READ(PIPESTAT(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note: this does not include DSI transcoders. */
|
||||||
error->num_transcoders = INTEL_INFO(dev)->num_pipes;
|
error->num_transcoders = INTEL_INFO(dev)->num_pipes;
|
||||||
if (HAS_DDI(dev_priv->dev))
|
if (HAS_DDI(dev_priv->dev))
|
||||||
error->num_transcoders++; /* Account for eDP. */
|
error->num_transcoders++; /* Account for eDP. */
|
||||||
|
|
|
@ -437,7 +437,8 @@ struct intel_crtc_state {
|
||||||
bool has_infoframe;
|
bool has_infoframe;
|
||||||
|
|
||||||
/* CPU Transcoder for the pipe. Currently this can only differ from the
|
/* CPU Transcoder for the pipe. Currently this can only differ from the
|
||||||
* pipe on Haswell (where we have a special eDP transcoder). */
|
* pipe on Haswell and later (where we have a special eDP transcoder)
|
||||||
|
* and Broxton (where we have special DSI transcoders). */
|
||||||
enum transcoder cpu_transcoder;
|
enum transcoder cpu_transcoder;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -268,6 +268,7 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
|
||||||
static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
||||||
struct intel_crtc_state *pipe_config)
|
struct intel_crtc_state *pipe_config)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
|
||||||
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
|
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
|
||||||
base);
|
base);
|
||||||
struct intel_connector *intel_connector = intel_dsi->attached_connector;
|
struct intel_connector *intel_connector = intel_dsi->attached_connector;
|
||||||
|
@ -284,6 +285,14 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
||||||
/* DSI uses short packets for sync events, so clear mode flags for DSI */
|
/* DSI uses short packets for sync events, so clear mode flags for DSI */
|
||||||
adjusted_mode->flags = 0;
|
adjusted_mode->flags = 0;
|
||||||
|
|
||||||
|
if (IS_BROXTON(dev_priv)) {
|
||||||
|
/* Dual link goes to DSI transcoder A. */
|
||||||
|
if (intel_dsi->ports == BIT(PORT_C))
|
||||||
|
pipe_config->cpu_transcoder = TRANSCODER_DSI_C;
|
||||||
|
else
|
||||||
|
pipe_config->cpu_transcoder = TRANSCODER_DSI_A;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,10 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
|
||||||
return "TRANSCODER_C";
|
return "TRANSCODER_C";
|
||||||
case POWER_DOMAIN_TRANSCODER_EDP:
|
case POWER_DOMAIN_TRANSCODER_EDP:
|
||||||
return "TRANSCODER_EDP";
|
return "TRANSCODER_EDP";
|
||||||
|
case POWER_DOMAIN_TRANSCODER_DSI_A:
|
||||||
|
return "TRANSCODER_DSI_A";
|
||||||
|
case POWER_DOMAIN_TRANSCODER_DSI_C:
|
||||||
|
return "TRANSCODER_DSI_C";
|
||||||
case POWER_DOMAIN_PORT_DDI_A_LANES:
|
case POWER_DOMAIN_PORT_DDI_A_LANES:
|
||||||
return "PORT_DDI_A_LANES";
|
return "PORT_DDI_A_LANES";
|
||||||
case POWER_DOMAIN_PORT_DDI_B_LANES:
|
case POWER_DOMAIN_PORT_DDI_B_LANES:
|
||||||
|
@ -419,6 +423,8 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
|
||||||
BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
|
BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
|
||||||
BIT(POWER_DOMAIN_PIPE_A) | \
|
BIT(POWER_DOMAIN_PIPE_A) | \
|
||||||
BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
|
BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
|
||||||
|
BIT(POWER_DOMAIN_TRANSCODER_DSI_A) | \
|
||||||
|
BIT(POWER_DOMAIN_TRANSCODER_DSI_C) | \
|
||||||
BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \
|
BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \
|
||||||
BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
|
BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
|
||||||
BIT(POWER_DOMAIN_PORT_DSI) | \
|
BIT(POWER_DOMAIN_PORT_DSI) | \
|
||||||
|
|
Loading…
Reference in New Issue