drm/i915/display: Support PSR Multiple Instances

It is a preliminary work for supporting multiple EDP PSR and
DP PanelReplay. And it refactors singleton PSR to Multi Transcoder
supportable PSR.
And this moves and renames the i915_psr structure of drm_i915_private's to
intel_dp's intel_psr structure.
It also causes changes in PSR interrupt handling routine for supporting
multiple transcoders. But it does not change the scenario and timing of
enabling and disabling PSR. And it not support multiple pipes with
a single transcoder PSR case yet.

v2: Fix indentation and add comments
v3: Remove Blank line
v4: Rebased
v5: Rebased and Addressed Anshuman's review comment.
    - Move calling of intel_psr_init() to intel_dp_init_connector()
v6: Address Anshuman's review comments
   - Remove wrong comments and add comments for a limit of supporting of
     a single pipe PSR
v7: Update intel_psr_compute_config() for supporting multiple transcoder
    PSR on BDW+
v8: Address Anshuman's review comments
   - Replace DRM_DEBUG_KMS with drm_dbg_kms() / DRM_WARN with drm_warn()
v9: Fix commit message
v10: Rebased
v11: Address Jose's review comment.
  - Reorder calling order of intel_psr2_program_trans_man_trk_ctl().
  - In order to reduce changes keep the old name for drm_i915_private.
  - Change restrictions of multiple instances of PSR.
v12: Address Jose's review comment.
  - Change the calling of intel_psr2_program_trans_man_trk_ctl() into
    commit_pipe_config().
  - Change a checking order of CAN_PSR() and connector_status to original
    on i915_psr_sink_status_show().
  - Drop unneeded intel_dp_update_pipe() function.
  - In order to wait a specific encoder which belong to crtc_state on
    intel_psr_wait_for_idle(), add checking of encoder.
  - Add an whitespace to comments.
v13: Rebased and Address Jose's review comment.
  - Add and use for_each_intel_psr_enabled_encoder() macro.
  - In order to use correct frontbuffer_bit for each pipe,
    fix intel_psr_invalidate() and intel_psr_flush().
  - Remove redundant or unneeded codes.
  - Update comments.
v14: Address Jose's review comment
  - Add and use for_each_intel_encoder_can_psr() macro and
    for_each_intel_encoder_mask_can_psr() macro.
  - Add source_support member variable into intel_psr structure.
  - Update CAN_PSR() macro that checks source_support.
  - Move encoder's PSR availity check to psr_init() from
    psr_compute_config().
  - Remove redundant or unneeded codes.
v15: Remove wrong mutex lock/unlock of PSR from
     intel_psr2_program_trans_man_trk_ctl()

Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: José Roberto de Souza <jose.souza@intel.com>
Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com>
Cc: Anshuman Gupta <anshuman.gupta@intel.com>
Reviewed-by: Anshuman Gupta <anshuman.gupta@intel.com>
Reviewed-by: José Roberto de Souza <jose.souza@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210204134015.419036-1-gwan-gyeong.mun@intel.com
This commit is contained in:
Gwan-gyeong Mun 2021-02-04 15:40:14 +02:00 committed by José Roberto de Souza
parent 1f1257a67c
commit b64d6c5138
10 changed files with 492 additions and 381 deletions

View File

@ -14155,8 +14155,6 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
intel_dvo_init(dev_priv);
}
intel_psr_init(dev_priv);
for_each_intel_encoder(&dev_priv->drm, encoder) {
encoder->base.possible_crtcs =
intel_encoder_possible_crtcs(encoder);

View File

@ -417,10 +417,19 @@ enum phy_fia {
for_each_if((encoder_mask) & \
drm_encoder_mask(&intel_encoder->base))
#define for_each_intel_encoder_mask_can_psr(dev, intel_encoder, encoder_mask) \
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
for_each_if(((encoder_mask) & drm_encoder_mask(&(intel_encoder)->base)) && \
intel_encoder_can_psr(intel_encoder))
#define for_each_intel_dp(dev, intel_encoder) \
for_each_intel_encoder(dev, intel_encoder) \
for_each_if(intel_encoder_is_dp(intel_encoder))
#define for_each_intel_encoder_can_psr(dev, intel_encoder) \
for_each_intel_encoder((dev), (intel_encoder)) \
for_each_if(intel_encoder_can_psr(intel_encoder))
#define for_each_intel_connector_iter(intel_connector, iter) \
while ((intel_connector = to_intel_connector(drm_connector_list_iter_next(iter))))

View File

@ -249,12 +249,11 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data)
"sink internal error",
};
struct drm_connector *connector = m->private;
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_dp *intel_dp =
intel_attached_dp(to_intel_connector(connector));
int ret;
if (!CAN_PSR(dev_priv)) {
if (!CAN_PSR(intel_dp)) {
seq_puts(m, "PSR Unsupported\n");
return -ENODEV;
}
@ -280,12 +279,13 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data)
DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status);
static void
psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m)
psr_source_status(struct intel_dp *intel_dp, struct seq_file *m)
{
u32 val, status_val;
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
const char *status = "unknown";
u32 val, status_val;
if (dev_priv->psr.psr2_enabled) {
if (intel_dp->psr.psr2_enabled) {
static const char * const live_status[] = {
"IDLE",
"CAPTURE",
@ -300,7 +300,7 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m)
"TG_ON"
};
val = intel_de_read(dev_priv,
EDP_PSR2_STATUS(dev_priv->psr.transcoder));
EDP_PSR2_STATUS(intel_dp->psr.transcoder));
status_val = (val & EDP_PSR2_STATUS_STATE_MASK) >>
EDP_PSR2_STATUS_STATE_SHIFT;
if (status_val < ARRAY_SIZE(live_status))
@ -317,7 +317,7 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m)
"SRDENT_ON",
};
val = intel_de_read(dev_priv,
EDP_PSR_STATUS(dev_priv->psr.transcoder));
EDP_PSR_STATUS(intel_dp->psr.transcoder));
status_val = (val & EDP_PSR_STATUS_STATE_MASK) >>
EDP_PSR_STATUS_STATE_SHIFT;
if (status_val < ARRAY_SIZE(live_status))
@ -327,21 +327,18 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m)
seq_printf(m, "Source PSR status: %s [0x%08x]\n", status, val);
}
static int i915_edp_psr_status(struct seq_file *m, void *data)
static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct i915_psr *psr = &dev_priv->psr;
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
struct intel_psr *psr = &intel_dp->psr;
intel_wakeref_t wakeref;
const char *status;
bool enabled;
u32 val;
if (!HAS_PSR(dev_priv))
return -ENODEV;
seq_printf(m, "Sink support: %s", yesno(psr->sink_support));
if (psr->dp)
seq_printf(m, " [0x%02x]", psr->dp->psr_dpcd[0]);
if (psr->sink_support)
seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]);
seq_puts(m, "\n");
if (!psr->sink_support)
@ -365,16 +362,16 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
if (psr->psr2_enabled) {
val = intel_de_read(dev_priv,
EDP_PSR2_CTL(dev_priv->psr.transcoder));
EDP_PSR2_CTL(intel_dp->psr.transcoder));
enabled = val & EDP_PSR2_ENABLE;
} else {
val = intel_de_read(dev_priv,
EDP_PSR_CTL(dev_priv->psr.transcoder));
EDP_PSR_CTL(intel_dp->psr.transcoder));
enabled = val & EDP_PSR_ENABLE;
}
seq_printf(m, "Source PSR ctl: %s [0x%08x]\n",
enableddisabled(enabled), val);
psr_source_status(dev_priv, m);
psr_source_status(intel_dp, m);
seq_printf(m, "Busy frontbuffer bits: 0x%08x\n",
psr->busy_frontbuffer_bits);
@ -383,7 +380,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
*/
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
val = intel_de_read(dev_priv,
EDP_PSR_PERF_CNT(dev_priv->psr.transcoder));
EDP_PSR_PERF_CNT(intel_dp->psr.transcoder));
val &= EDP_PSR_PERF_CNT_MASK;
seq_printf(m, "Performance counter: %u\n", val);
}
@ -404,7 +401,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
*/
for (frame = 0; frame < PSR2_SU_STATUS_FRAMES; frame += 3) {
val = intel_de_read(dev_priv,
PSR2_SU_STATUS(dev_priv->psr.transcoder, frame));
PSR2_SU_STATUS(intel_dp->psr.transcoder, frame));
su_frames_val[frame / 3] = val;
}
@ -430,23 +427,50 @@ unlock:
return 0;
}
static int i915_edp_psr_status(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct intel_dp *intel_dp = NULL;
struct intel_encoder *encoder;
if (!HAS_PSR(dev_priv))
return -ENODEV;
/* Find the first EDP which supports PSR */
for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) {
intel_dp = enc_to_intel_dp(encoder);
break;
}
if (!intel_dp)
return -ENODEV;
return intel_psr_status(m, intel_dp);
}
static int
i915_edp_psr_debug_set(void *data, u64 val)
{
struct drm_i915_private *dev_priv = data;
struct intel_encoder *encoder;
intel_wakeref_t wakeref;
int ret;
int ret = -ENODEV;
if (!CAN_PSR(dev_priv))
return -ENODEV;
if (!HAS_PSR(dev_priv))
return ret;
drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val);
for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val);
ret = intel_psr_debug_set(dev_priv, val);
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
// TODO: split to each transcoder's PSR debug state
ret = intel_psr_debug_set(intel_dp, val);
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
}
return ret;
}
@ -455,12 +479,20 @@ static int
i915_edp_psr_debug_get(void *data, u64 *val)
{
struct drm_i915_private *dev_priv = data;
struct intel_encoder *encoder;
if (!CAN_PSR(dev_priv))
if (!HAS_PSR(dev_priv))
return -ENODEV;
*val = READ_ONCE(dev_priv->psr.debug);
return 0;
for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
// TODO: split to each transcoder's PSR debug state
*val = READ_ONCE(intel_dp->psr.debug);
return 0;
}
return -ENODEV;
}
DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops,
@ -1233,9 +1265,6 @@ static void drrs_status_per_crtc(struct seq_file *m,
/* disable_drrs() will make drrs->dp NULL */
if (!drrs->dp) {
seq_puts(m, "Idleness DRRS: Disabled\n");
if (dev_priv->psr.enabled)
seq_puts(m,
"\tAs PSR is enabled, DRRS is not enabled\n");
mutex_unlock(&drrs->mutex);
return;
}

View File

@ -1415,6 +1415,43 @@ struct intel_pps {
struct edp_power_seq pps_delays;
};
struct intel_psr {
/* Mutex for PSR state of the transcoder */
struct mutex lock;
#define I915_PSR_DEBUG_MODE_MASK 0x0f
#define I915_PSR_DEBUG_DEFAULT 0x00
#define I915_PSR_DEBUG_DISABLE 0x01
#define I915_PSR_DEBUG_ENABLE 0x02
#define I915_PSR_DEBUG_FORCE_PSR1 0x03
#define I915_PSR_DEBUG_IRQ 0x10
u32 debug;
bool sink_support;
bool source_support;
bool enabled;
enum pipe pipe;
enum transcoder transcoder;
bool active;
struct work_struct work;
unsigned int busy_frontbuffer_bits;
bool sink_psr2_support;
bool link_standby;
bool colorimetry_support;
bool psr2_enabled;
bool psr2_sel_fetch_enabled;
u8 sink_sync_latency;
ktime_t last_entry_attempt;
ktime_t last_exit;
bool sink_not_reliable;
bool irq_aux_error;
u16 su_x_granularity;
bool dc3co_enabled;
u32 dc3co_exit_delay;
struct delayed_work dc3co_work;
struct drm_dp_vsc_sdp vsc;
};
struct intel_dp {
i915_reg_t output_reg;
u32 DP;
@ -1517,6 +1554,8 @@ struct intel_dp {
bool hobl_active;
struct intel_dp_pcon_frl frl;
struct intel_psr psr;
};
enum lspcon_vendor {
@ -1753,6 +1792,18 @@ dp_to_i915(struct intel_dp *intel_dp)
return to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
}
#define CAN_PSR(intel_dp) (HAS_PSR(dp_to_i915(intel_dp)) && \
(intel_dp)->psr.sink_support && \
(intel_dp)->psr.source_support)
static inline bool intel_encoder_can_psr(struct intel_encoder *encoder)
{
if (!intel_encoder_is_dp(encoder))
return false;
return CAN_PSR(enc_to_intel_dp(encoder));
}
static inline struct intel_digital_port *
hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
{

View File

@ -1663,12 +1663,10 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
const struct drm_connector_state *conn_state,
struct drm_dp_vsc_sdp *vsc)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
vsc->sdp_type = DP_SDP_VSC;
if (dev_priv->psr.psr2_enabled) {
if (dev_priv->psr.colorimetry_support &&
if (intel_dp->psr.psr2_enabled) {
if (intel_dp->psr.colorimetry_support &&
intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
/* [PSR2, +Colorimetry] */
intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
@ -2359,7 +2357,7 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
return false;
}
if (CAN_PSR(i915) && intel_dp_is_edp(intel_dp)) {
if (CAN_PSR(intel_dp) && intel_dp_is_edp(intel_dp)) {
drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n");
crtc_state->uapi.mode_changed = true;
return false;
@ -6641,6 +6639,8 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
intel_dp->frl.is_trained = false;
intel_dp->frl.trained_rate_gbps = 0;
intel_psr_init(intel_dp);
return true;
fail:

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,6 @@ struct intel_atomic_state;
struct intel_plane_state;
struct intel_plane;
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
void intel_psr_init_dpcd(struct intel_dp *intel_dp);
void intel_psr_enable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
@ -28,20 +27,19 @@ void intel_psr_disable(struct intel_dp *intel_dp,
void intel_psr_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
int intel_psr_debug_set(struct drm_i915_private *dev_priv, u64 value);
int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value);
void intel_psr_invalidate(struct drm_i915_private *dev_priv,
unsigned frontbuffer_bits,
enum fb_op_origin origin);
void intel_psr_flush(struct drm_i915_private *dev_priv,
unsigned frontbuffer_bits,
enum fb_op_origin origin);
void intel_psr_init(struct drm_i915_private *dev_priv);
void intel_psr_init(struct intel_dp *intel_dp);
void intel_psr_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state);
void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir);
void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
void intel_psr_short_pulse(struct intel_dp *intel_dp);
int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state,
u32 *out_value);
void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state);
bool intel_psr_enabled(struct intel_dp *intel_dp);
int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);

View File

@ -96,7 +96,6 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
DEFINE_WAIT(wait);
u32 psr_status;
if (new_crtc_state->uapi.async_flip)
return;
@ -122,10 +121,7 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
* VBL interrupts will start the PSR exit and prevent a PSR
* re-entry as well.
*/
if (intel_psr_wait_for_idle(new_crtc_state, &psr_status))
drm_err(&dev_priv->drm,
"PSR idle timed out 0x%x, atomic update may fail\n",
psr_status);
intel_psr_wait_for_idle(new_crtc_state);
local_irq_disable();

View File

@ -475,42 +475,6 @@ struct i915_drrs {
enum drrs_support_type type;
};
struct i915_psr {
struct mutex lock;
#define I915_PSR_DEBUG_MODE_MASK 0x0f
#define I915_PSR_DEBUG_DEFAULT 0x00
#define I915_PSR_DEBUG_DISABLE 0x01
#define I915_PSR_DEBUG_ENABLE 0x02
#define I915_PSR_DEBUG_FORCE_PSR1 0x03
#define I915_PSR_DEBUG_IRQ 0x10
u32 debug;
bool sink_support;
bool enabled;
struct intel_dp *dp;
enum pipe pipe;
enum transcoder transcoder;
bool active;
struct work_struct work;
unsigned busy_frontbuffer_bits;
bool sink_psr2_support;
bool link_standby;
bool colorimetry_support;
bool psr2_enabled;
bool psr2_sel_fetch_enabled;
u8 sink_sync_latency;
ktime_t last_entry_attempt;
ktime_t last_exit;
bool sink_not_reliable;
bool irq_aux_error;
u16 su_x_granularity;
bool dc3co_enabled;
u32 dc3co_exit_delay;
struct delayed_work dc3co_work;
struct drm_dp_vsc_sdp vsc;
};
#define QUIRK_LVDS_SSC_DISABLE (1<<1)
#define QUIRK_INVERT_BRIGHTNESS (1<<2)
#define QUIRK_BACKLIGHT_PRESENT (1<<3)
@ -1038,8 +1002,6 @@ struct drm_i915_private {
struct i915_power_domains power_domains;
struct i915_psr psr;
struct i915_gpu_error gpu_error;
struct drm_i915_gem_object *vlv_pctx;

View File

@ -2094,10 +2094,19 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
ivb_err_int_handler(dev_priv);
if (de_iir & DE_EDP_PSR_INT_HSW) {
u32 psr_iir = intel_uncore_read(&dev_priv->uncore, EDP_PSR_IIR);
struct intel_encoder *encoder;
intel_psr_irq_handler(dev_priv, psr_iir);
intel_uncore_write(&dev_priv->uncore, EDP_PSR_IIR, psr_iir);
for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
u32 psr_iir = intel_uncore_read(&dev_priv->uncore,
EDP_PSR_IIR);
intel_psr_irq_handler(intel_dp, psr_iir);
intel_uncore_write(&dev_priv->uncore,
EDP_PSR_IIR, psr_iir);
break;
}
}
if (de_iir & DE_AUX_CHANNEL_A_IVB)
@ -2310,21 +2319,30 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
}
if (iir & GEN8_DE_EDP_PSR) {
struct intel_encoder *encoder;
u32 psr_iir;
i915_reg_t iir_reg;
if (INTEL_GEN(dev_priv) >= 12)
iir_reg = TRANS_PSR_IIR(dev_priv->psr.transcoder);
else
iir_reg = EDP_PSR_IIR;
for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
psr_iir = intel_uncore_read(&dev_priv->uncore, iir_reg);
intel_uncore_write(&dev_priv->uncore, iir_reg, psr_iir);
if (INTEL_GEN(dev_priv) >= 12)
iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder);
else
iir_reg = EDP_PSR_IIR;
if (psr_iir)
found = true;
psr_iir = intel_uncore_read(&dev_priv->uncore, iir_reg);
intel_uncore_write(&dev_priv->uncore, iir_reg, psr_iir);
intel_psr_irq_handler(dev_priv, psr_iir);
if (psr_iir)
found = true;
intel_psr_irq_handler(intel_dp, psr_iir);
/* prior GEN12 only have one EDP PSR */
if (INTEL_GEN(dev_priv) < 12)
break;
}
}
if (!found)