diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5c45e9e598de..7c29a8827177 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1936,6 +1936,7 @@ static const char * const pipe_crc_sources[] = { "DP-B", "DP-C", "DP-D", + "auto", }; static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) @@ -1964,10 +1965,13 @@ static int display_crc_ctl_open(struct inode *inode, struct file *file) return single_open(file, display_crc_ctl_show, dev); } -static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, +static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, uint32_t *val) { - switch (source) { + if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) + *source = INTEL_PIPE_CRC_SOURCE_PIPE; + + switch (*source) { case INTEL_PIPE_CRC_SOURCE_PIPE: *val = PIPE_CRC_ENABLE | PIPE_CRC_INCLUDE_BORDER_I8XX; break; @@ -1981,10 +1985,54 @@ static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, return 0; } -static int vlv_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, +static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe, + enum intel_pipe_crc_source *source) +{ + struct intel_encoder *encoder; + struct intel_crtc *crtc; + int ret = 0; + + *source = INTEL_PIPE_CRC_SOURCE_PIPE; + + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (!encoder->base.crtc) + continue; + + crtc = to_intel_crtc(encoder->base.crtc); + + if (crtc->pipe != pipe) + continue; + + switch (encoder->type) { + case INTEL_OUTPUT_TVOUT: + *source = INTEL_PIPE_CRC_SOURCE_TV; + break; + case INTEL_OUTPUT_DISPLAYPORT: + case INTEL_OUTPUT_EDP: + /* We can't get stable CRCs for DP ports somehow. */ + ret = -ENODEV; + break; + } + } + mutex_unlock(&dev->mode_config.mutex); + + return ret; +} + +static int vlv_pipe_crc_ctl_reg(struct drm_device *dev, + enum pipe pipe, + enum intel_pipe_crc_source *source, uint32_t *val) { - switch (source) { + if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) { + int ret = i9xx_pipe_crc_auto_source(dev, pipe, source); + if (ret) + return ret; + } + + switch (*source) { case INTEL_PIPE_CRC_SOURCE_PIPE: *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_VLV; break; @@ -2005,10 +2053,17 @@ static int vlv_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, } static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev, - enum intel_pipe_crc_source source, + enum pipe pipe, + enum intel_pipe_crc_source *source, uint32_t *val) { - switch (source) { + if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) { + int ret = i9xx_pipe_crc_auto_source(dev, pipe, source); + if (ret) + return ret; + } + + switch (*source) { case INTEL_PIPE_CRC_SOURCE_PIPE: *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PIPE_I9XX; break; @@ -2042,10 +2097,13 @@ static int i9xx_pipe_crc_ctl_reg(struct drm_device *dev, return 0; } -static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, +static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, uint32_t *val) { - switch (source) { + if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) + *source = INTEL_PIPE_CRC_SOURCE_PIPE; + + switch (*source) { case INTEL_PIPE_CRC_SOURCE_PLANE1: *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_ILK; break; @@ -2065,10 +2123,13 @@ static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, return 0; } -static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source source, +static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, uint32_t *val) { - switch (source) { + if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) + *source = INTEL_PIPE_CRC_SOURCE_PF; + + switch (*source) { case INTEL_PIPE_CRC_SOURCE_PLANE1: *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PRIMARY_IVB; break; @@ -2104,15 +2165,15 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, return -EINVAL; if (IS_GEN2(dev)) - ret = i8xx_pipe_crc_ctl_reg(source, &val); + ret = i8xx_pipe_crc_ctl_reg(&source, &val); else if (INTEL_INFO(dev)->gen < 5) - ret = i9xx_pipe_crc_ctl_reg(dev, source, &val); + ret = i9xx_pipe_crc_ctl_reg(dev, pipe, &source, &val); else if (IS_VALLEYVIEW(dev)) - ret = vlv_pipe_crc_ctl_reg(source, &val); + ret = vlv_pipe_crc_ctl_reg(dev,pipe, &source, &val); else if (IS_GEN5(dev) || IS_GEN6(dev)) - ret = ilk_pipe_crc_ctl_reg(source, &val); + ret = ilk_pipe_crc_ctl_reg(&source, &val); else - ret = ivb_pipe_crc_ctl_reg(source, &val); + ret = ivb_pipe_crc_ctl_reg(&source, &val); if (ret != 0) return ret; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0a886fd24936..f2324bc46800 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1251,6 +1251,7 @@ enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_DP_B, INTEL_PIPE_CRC_SOURCE_DP_C, INTEL_PIPE_CRC_SOURCE_DP_D, + INTEL_PIPE_CRC_SOURCE_AUTO, INTEL_PIPE_CRC_SOURCE_MAX, };