From 5334240c30cb0058fa8c373bf0d653337833230d Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 2 Sep 2015 14:11:38 +0800 Subject: [PATCH 001/134] drm/i915: Add audio sync_audio_rate callback Add the sync_audio_rate callback. With the callback, audio driver can trigger i915 driver to set the proper N/CTS or N/M based on different sample rates. Signed-off-by: Libin Yang Reviewed-by: Jani Nikula Signed-off-by: Takashi Iwai --- include/drm/i915_component.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index b2d56dd483d9..e6d35d7239c0 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -33,6 +33,13 @@ struct i915_audio_component { void (*put_power)(struct device *); void (*codec_wake_override)(struct device *, bool enable); int (*get_cdclk_freq)(struct device *); + /** + * @sync_audio_rate: set n/cts based on the sample rate + * + * Called from audio driver. After audio driver sets the + * sample rate, it will call this function to set n/cts + */ + int (*sync_audio_rate)(struct device *, int port, int rate); } *ops; const struct i915_audio_component_audio_ops { From 4a21ef7d1d2b19fdd986783e9ef53bd15fdc87bf Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 2 Sep 2015 14:11:39 +0800 Subject: [PATCH 002/134] drm/i915: implement sync_audio_rate callback HDMI audio may not work at some frequencies with the HW provided N/CTS. This patch sets the proper N value for the given audio sample rate at the impacted frequencies. At other frequencies, it will use the N/CTS value which HW provides. Signed-off-by: Libin Yang Reviewed-by: Jani Nikula Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 5 ++ drivers/gpu/drm/i915/intel_audio.c | 138 +++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ab37d1121be8..990f656e6ab0 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -832,6 +832,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) mutex_init(&dev_priv->sb_lock); mutex_init(&dev_priv->modeset_restore_lock); mutex_init(&dev_priv->csr_lock); + mutex_init(&dev_priv->av_mutex); intel_pm_setup(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e1db8de52851..22dd7043c9ef 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1885,6 +1885,11 @@ struct drm_i915_private { /* hda/i915 audio component */ struct i915_audio_component *audio_component; bool audio_component_registered; + /** + * av_mutex - mutex for audio/video sync + * + */ + struct mutex av_mutex; uint32_t hw_context_size; struct list_head context_list; diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 89c1a8ce1f98..c5922f902aaf 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -68,6 +68,31 @@ static const struct { { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 }, }; +/* HDMI N/CTS table */ +#define TMDS_297M 297000 +#define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001) +static const struct { + int sample_rate; + int clock; + int n; + int cts; +} aud_ncts[] = { + { 44100, TMDS_296M, 4459, 234375 }, + { 44100, TMDS_297M, 4704, 247500 }, + { 48000, TMDS_296M, 5824, 281250 }, + { 48000, TMDS_297M, 5120, 247500 }, + { 32000, TMDS_296M, 5824, 421875 }, + { 32000, TMDS_297M, 3072, 222750 }, + { 88200, TMDS_296M, 8918, 234375 }, + { 88200, TMDS_297M, 9408, 247500 }, + { 96000, TMDS_296M, 11648, 281250 }, + { 96000, TMDS_297M, 10240, 247500 }, + { 176400, TMDS_296M, 17836, 234375 }, + { 176400, TMDS_297M, 18816, 247500 }, + { 192000, TMDS_296M, 23296, 281250 }, + { 192000, TMDS_297M, 20480, 247500 }, +}; + /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) { @@ -90,6 +115,31 @@ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) return hdmi_audio_clock[i].config; } +static int audio_config_get_n(const struct drm_display_mode *mode, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(aud_ncts); i++) { + if ((rate == aud_ncts[i].sample_rate) && + (mode->clock == aud_ncts[i].clock)) { + return aud_ncts[i].n; + } + } + return 0; +} + +/* check whether N/CTS/M need be set manually */ +static bool audio_rate_need_prog(struct intel_crtc *crtc, + struct drm_display_mode *mode) +{ + if (((mode->clock == TMDS_297M) || + (mode->clock == TMDS_296M)) && + intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) + return true; + else + return false; +} + static bool intel_eld_uptodate(struct drm_connector *connector, int reg_eldv, uint32_t bits_eldv, int reg_elda, uint32_t bits_elda, @@ -184,6 +234,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe)); + mutex_lock(&dev_priv->av_mutex); + /* Disable timestamps */ tmp = I915_READ(HSW_AUD_CFG(pipe)); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; @@ -199,6 +251,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder) tmp &= ~AUDIO_ELD_VALID(pipe); tmp &= ~AUDIO_OUTPUT_ENABLE(pipe); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + + mutex_unlock(&dev_priv->av_mutex); } static void hsw_audio_codec_enable(struct drm_connector *connector, @@ -215,6 +269,8 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n", pipe_name(pipe), drm_eld_size(eld)); + mutex_lock(&dev_priv->av_mutex); + /* Enable audio presence detect, invalidate ELD */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); tmp |= AUDIO_OUTPUT_ENABLE(pipe); @@ -253,6 +309,8 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, else tmp |= audio_config_hdmi_pixel_clock(mode); I915_WRITE(HSW_AUD_CFG(pipe), tmp); + + mutex_unlock(&dev_priv->av_mutex); } static void ilk_audio_codec_disable(struct intel_encoder *encoder) @@ -527,12 +585,92 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev) return ret; } +static int i915_audio_component_sync_audio_rate(struct device *dev, + int port, int rate) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + struct drm_device *drm_dev = dev_priv->dev; + struct intel_encoder *intel_encoder; + struct intel_digital_port *intel_dig_port; + struct intel_crtc *crtc; + struct drm_display_mode *mode; + enum pipe pipe = -1; + u32 tmp; + int n_low, n_up, n; + + /* HSW, BDW SKL need this fix */ + if (!IS_SKYLAKE(dev_priv) && + !IS_BROADWELL(dev_priv) && + !IS_HASWELL(dev_priv)) + return 0; + + mutex_lock(&dev_priv->av_mutex); + /* 1. get the pipe */ + for_each_intel_encoder(drm_dev, intel_encoder) { + if (intel_encoder->type != INTEL_OUTPUT_HDMI) + continue; + intel_dig_port = enc_to_dig_port(&intel_encoder->base); + if (port == intel_dig_port->port) { + crtc = to_intel_crtc(intel_encoder->base.crtc); + if (!crtc) { + DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__); + continue; + } + pipe = crtc->pipe; + break; + } + } + + if (pipe == INVALID_PIPE) { + DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port)); + mutex_unlock(&dev_priv->av_mutex); + return -ENODEV; + } + DRM_DEBUG_KMS("pipe %c connects port %c\n", + pipe_name(pipe), port_name(port)); + mode = &crtc->config->base.adjusted_mode; + + /* 2. check whether to set the N/CTS/M manually or not */ + if (!audio_rate_need_prog(crtc, mode)) { + tmp = I915_READ(HSW_AUD_CFG(pipe)); + tmp &= ~AUD_CONFIG_N_PROG_ENABLE; + I915_WRITE(HSW_AUD_CFG(pipe), tmp); + mutex_unlock(&dev_priv->av_mutex); + return 0; + } + + n = audio_config_get_n(mode, rate); + if (n == 0) { + DRM_DEBUG_KMS("Using automatic mode for N value on port %c\n", + port_name(port)); + tmp = I915_READ(HSW_AUD_CFG(pipe)); + tmp &= ~AUD_CONFIG_N_PROG_ENABLE; + I915_WRITE(HSW_AUD_CFG(pipe), tmp); + mutex_unlock(&dev_priv->av_mutex); + return 0; + } + n_low = n & 0xfff; + n_up = (n >> 12) & 0xff; + + /* 4. set the N/CTS/M */ + tmp = I915_READ(HSW_AUD_CFG(pipe)); + tmp &= ~(AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK); + tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) | + (n_low << AUD_CONFIG_LOWER_N_SHIFT) | + AUD_CONFIG_N_PROG_ENABLE); + I915_WRITE(HSW_AUD_CFG(pipe), tmp); + + mutex_unlock(&dev_priv->av_mutex); + return 0; +} + static const struct i915_audio_component_ops i915_audio_component_ops = { .owner = THIS_MODULE, .get_power = i915_audio_component_get_power, .put_power = i915_audio_component_put_power, .codec_wake_override = i915_audio_component_codec_wake_override, .get_cdclk_freq = i915_audio_component_get_cdclk_freq, + .sync_audio_rate = i915_audio_component_sync_audio_rate, }; static int i915_audio_component_bind(struct device *i915_dev, From ddd621fbba35178643a39559c9688a373285bbc0 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 2 Sep 2015 14:11:40 +0800 Subject: [PATCH 003/134] ALSA: hda - display audio call sync_audio_rate callback For display audio, call the sync_audio_rate callback function to do the synchronization between gfx driver and audio driver. Signed-off-by: Libin Yang Reviewed-by: Takashi Iwai Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index acbfbe087ee8..3a2d4a5a1714 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1775,6 +1775,16 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) return non_pcm; } +/* There is a fixed mapping between audio pin node and display port + * on current Intel platforms: + * Pin Widget 5 - PORT B (port = 1 in i915 driver) + * Pin Widget 6 - PORT C (port = 2 in i915 driver) + * Pin Widget 7 - PORT D (port = 3 in i915 driver) + */ +static int intel_pin2port(hda_nid_t pin_nid) +{ + return pin_nid - 4; +} /* * HDMI callbacks @@ -1791,6 +1801,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, int pin_idx = hinfo_to_pin_index(codec, hinfo); struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; + struct snd_pcm_runtime *runtime = substream->runtime; + struct i915_audio_component *acomp = codec->bus->core.audio_component; bool non_pcm; int pinctl; @@ -1807,6 +1819,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); } + /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ + /* Todo: add DP1.2 MST audio support later */ + if (acomp && acomp->ops && acomp->ops->sync_audio_rate) + acomp->ops->sync_audio_rate(acomp->dev, + intel_pin2port(pin_nid), + runtime->rate); + non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); per_pin->channels = substream->runtime->channels; From 7e8275c2f2bbb384e18af37066b8b2f32b7d092f Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Fri, 25 Sep 2015 09:36:12 +0800 Subject: [PATCH 004/134] drm/i915: set proper N/CTS in modeset When modeset occurs and the TMDS frequency is set to some speical values, the N/CTS need to be set manually if audio is playing. Signed-off-by: Libin Yang Reviewed-by: Jani Nikula Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_audio.c | 57 +++++++++++++++++++++++++----- include/drm/i915_component.h | 10 ++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index c5922f902aaf..30f6859dcb36 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -128,6 +128,20 @@ static int audio_config_get_n(const struct drm_display_mode *mode, int rate) return 0; } +static uint32_t audio_config_setup_n_reg(int n, uint32_t val) +{ + int n_low, n_up; + uint32_t tmp = val; + + n_low = n & 0xfff; + n_up = (n >> 12) & 0xff; + tmp &= ~(AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK); + tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) | + (n_low << AUD_CONFIG_LOWER_N_SHIFT) | + AUD_CONFIG_N_PROG_ENABLE); + return tmp; +} + /* check whether N/CTS/M need be set manually */ static bool audio_rate_need_prog(struct intel_crtc *crtc, struct drm_display_mode *mode) @@ -262,9 +276,14 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); enum pipe pipe = intel_crtc->pipe; + struct i915_audio_component *acomp = dev_priv->audio_component; const uint8_t *eld = connector->eld; + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(&encoder->base); + enum port port = intel_dig_port->port; uint32_t tmp; int len, i; + int n, rate; DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n", pipe_name(pipe), drm_eld_size(eld)); @@ -302,12 +321,29 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, /* Enable timestamps */ tmp = I915_READ(HSW_AUD_CFG(pipe)); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; - tmp &= ~AUD_CONFIG_N_PROG_ENABLE; tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) tmp |= AUD_CONFIG_N_VALUE_INDEX; else tmp |= audio_config_hdmi_pixel_clock(mode); + + tmp &= ~AUD_CONFIG_N_PROG_ENABLE; + if (audio_rate_need_prog(intel_crtc, mode)) { + if (!acomp) + rate = 0; + else if (port >= PORT_A && port <= PORT_E) + rate = acomp->aud_sample_rate[port]; + else { + DRM_ERROR("invalid port: %d\n", port); + rate = 0; + } + n = audio_config_get_n(mode, rate); + if (n != 0) + tmp = audio_config_setup_n_reg(n, tmp); + else + DRM_DEBUG_KMS("no suitable N value is found\n"); + } + I915_WRITE(HSW_AUD_CFG(pipe), tmp); mutex_unlock(&dev_priv->av_mutex); @@ -594,9 +630,10 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, struct intel_digital_port *intel_dig_port; struct intel_crtc *crtc; struct drm_display_mode *mode; + struct i915_audio_component *acomp = dev_priv->audio_component; enum pipe pipe = -1; u32 tmp; - int n_low, n_up, n; + int n; /* HSW, BDW SKL need this fix */ if (!IS_SKYLAKE(dev_priv) && @@ -630,6 +667,9 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, pipe_name(pipe), port_name(port)); mode = &crtc->config->base.adjusted_mode; + /* port must be valid now, otherwise the pipe will be invalid */ + acomp->aud_sample_rate[port] = rate; + /* 2. check whether to set the N/CTS/M manually or not */ if (!audio_rate_need_prog(crtc, mode)) { tmp = I915_READ(HSW_AUD_CFG(pipe)); @@ -649,15 +689,10 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, mutex_unlock(&dev_priv->av_mutex); return 0; } - n_low = n & 0xfff; - n_up = (n >> 12) & 0xff; - /* 4. set the N/CTS/M */ + /* 3. set the N/CTS/M */ tmp = I915_READ(HSW_AUD_CFG(pipe)); - tmp &= ~(AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK); - tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) | - (n_low << AUD_CONFIG_LOWER_N_SHIFT) | - AUD_CONFIG_N_PROG_ENABLE); + tmp = audio_config_setup_n_reg(n, tmp); I915_WRITE(HSW_AUD_CFG(pipe), tmp); mutex_unlock(&dev_priv->av_mutex); @@ -678,6 +713,7 @@ static int i915_audio_component_bind(struct device *i915_dev, { struct i915_audio_component *acomp = data; struct drm_i915_private *dev_priv = dev_to_i915(i915_dev); + int i; if (WARN_ON(acomp->ops || acomp->dev)) return -EEXIST; @@ -685,6 +721,9 @@ static int i915_audio_component_bind(struct device *i915_dev, drm_modeset_lock_all(dev_priv->dev); acomp->ops = &i915_audio_component_ops; acomp->dev = i915_dev; + BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS); + for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++) + acomp->aud_sample_rate[i] = 0; dev_priv->audio_component = acomp; drm_modeset_unlock_all(dev_priv->dev); diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index e6d35d7239c0..89dc7d6bc1cc 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -24,8 +24,18 @@ #ifndef _I915_COMPONENT_H_ #define _I915_COMPONENT_H_ +/* MAX_PORT is the number of port + * It must be sync with I915_MAX_PORTS defined i915_drv.h + * 5 should be enough as only HSW, BDW, SKL need such fix. + */ +#define MAX_PORTS 5 + struct i915_audio_component { struct device *dev; + /** + * @aud_sample_rate: the array of audio sample rate per port + */ + int aud_sample_rate[MAX_PORTS]; const struct i915_audio_component_ops { struct module *owner; From 30c964a6cb7bbade28eabcbc3fce4b01be8f1a39 Mon Sep 17 00:00:00 2001 From: Robert Beckett Date: Fri, 28 Aug 2015 13:10:22 +0100 Subject: [PATCH 005/134] drm/i915: Detect virtual south bridge Virtualized systems often use a virtual P2X4 south bridge. Detect this in intel_detect_pch and make a best guess as to which PCH we should be using. This was seen on vmware esxi hypervisor. When passing the graphics device through to a guest, it can not pass through the PCH. Instead it simulates a P2X4 southbridge. Signed-off-by: Robert Beckett Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 30 ++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e6d7a69ec1bf..b31485a8bd39 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -443,6 +443,34 @@ static const struct pci_device_id pciidlist[] = { /* aka */ MODULE_DEVICE_TABLE(pci, pciidlist); +static enum intel_pch intel_virt_detect_pch(struct drm_device *dev) +{ + enum intel_pch ret = PCH_NOP; + + /* + * In a virtualized passthrough environment we can be in a + * setup where the ISA bridge is not able to be passed through. + * In this case, a south bridge can be emulated and we have to + * make an educated guess as to which PCH is really there. + */ + + if (IS_GEN5(dev)) { + ret = PCH_IBX; + DRM_DEBUG_KMS("Assuming Ibex Peak PCH\n"); + } else if (IS_GEN6(dev) || IS_IVYBRIDGE(dev)) { + ret = PCH_CPT; + DRM_DEBUG_KMS("Assuming CouarPoint PCH\n"); + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + ret = PCH_LPT; + DRM_DEBUG_KMS("Assuming LynxPoint PCH\n"); + } else if (IS_SKYLAKE(dev)) { + ret = PCH_SPT; + DRM_DEBUG_KMS("Assuming SunrisePoint PCH\n"); + } + + return ret; +} + void intel_detect_pch(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -503,6 +531,8 @@ void intel_detect_pch(struct drm_device *dev) dev_priv->pch_type = PCH_SPT; DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); WARN_ON(!IS_SKYLAKE(dev)); + } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) { + dev_priv->pch_type = intel_virt_detect_pch(dev); } else continue; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7d83f6741e33..04d710ff4913 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2608,6 +2608,7 @@ struct drm_i915_cmd_table { #define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00 #define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100 #define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00 +#define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type) #define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT) From 4b7ab5fca1976a53d59ef1558ddb06ba69fab356 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 26 Aug 2015 01:36:05 +0530 Subject: [PATCH 006/134] drm/i915/skl: Added a check for the hardware status of csr fw before loading. Dmc will restore the csr program except DC9, cold boot, warm reset, PCI function level reset, and hibernate/suspend. intel_csr_load_program() function is used to load the firmware data from kernel memory to csr address space. All values of csr address space will be zero if it got reset and the first byte of csr program is always a non-zero if firmware is loaded successfuly. Based on hardware status will load the firmware. Without this condition check if we overwrite the firmware data the counters exposed for dc5/dc6 (help for debugging) will be nullified. Note: Above commit message seems to be confused and the real problem apparently going on is that for suspend-to-idle and system standby the firmware survives (it's like runtime pm), but it doesn't for suspend-to-mem and hibernate-to-disk. All the other talking about DC9 and pci reset are irrelevant for the path touched here (only driver load and system resume functions) and might not be true statements. v1: Initial version. v2: Based on review comments from Daniel, - Added a check to know hardware status and load the firmware if not loaded. Cc: Daniel Vetter Cc: Damien Lespiau Cc: Imre Deak Cc: Sunil Kamath Signed-off-by: Animesh Manna Signed-off-by: Vathsala Nagaraju Reviewed-by: A.Sunil Kamath [danvet: Explain clearly in the code comment when we need to reload and when not and make it a FIXME. Also deconfuse the commit message with a note. Also: Make. it. compile.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 3427dd41d682..9e530a739354 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -265,6 +265,15 @@ void intel_csr_load_program(struct drm_device *dev) return; } + /* + * FIXME: Firmware gets lost on S3/S4, but not when entering system + * standby or suspend-to-idle (which is just like forced runtime pm). + * Unfortunately the ACPI subsystem doesn't yet give us a way to + * differentiate this, hence figure it out with this hack. + */ + if (I915_READ(CSR_PROGRAM(0))) + return; + mutex_lock(&dev_priv->csr_lock); fw_size = dev_priv->csr.dmc_fw_size; for (i = 0; i < fw_size; i++) From c268444a2cecabc0ab567ca275662d80fa0ac813 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 26 Aug 2015 01:36:06 +0530 Subject: [PATCH 007/134] drm/i915/skl Remove the call for csr uninitialization from suspend path This patch remove the function call to set the firmware loading status as uninitialized during suspend. Dmc firmware will restore the firmware in normal suspend. In previous patch added a check to directly read the hardware status and load the firmware if got reset during resume from suspend-hibernation. Cc: Daniel Vetter Signed-off-by: Animesh Manna Signed-off-by: Vathsala Nagaraju Reviewed-by: A.Sunil Kamath Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b31485a8bd39..1cb6b82e17d4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1051,12 +1051,6 @@ static int skl_suspend_complete(struct drm_i915_private *dev_priv) { /* Enabling DC6 is not a hard requirement to enter runtime D3 */ - /* - * This is to ensure that CSR isn't identified as loaded before - * CSR-loading program is called during runtime-resume. - */ - intel_csr_load_status_set(dev_priv, FW_UNINITIALIZED); - skl_uninit_cdclk(dev_priv); return 0; From 4e961e426cdeb5c9f27d65fb0afb0010fcecfeae Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 26 Aug 2015 01:36:08 +0530 Subject: [PATCH 008/134] drm/i915/skl: Do not disable cdclk PLL if csr firmware is present While display engine entering into low power state no need to disable cdclk pll as CSR firmware of dmc will take care. If pll is already enabled firmware execution sequence will be blocked. This is one of the criteria for dmc to work properly. v1: Initial version. v2: Based on review comment from Daniel added code commnent. Cc: Daniel Vetter Cc: Damien Lespiau Cc: Imre Deak Cc: Sunil Kamath Signed-off-by: Animesh Manna Signed-off-bt: Vathsala Nagaraju Signed-off-by: Rajneesh Bhardwaj Reviewed-by: A.Sunil Kamath Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 184725770ae7..5d8645ee3294 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5709,10 +5709,16 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv) if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) DRM_ERROR("DBuf power disable timeout\n"); - /* disable DPLL0 */ - I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE); - if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1)) - DRM_ERROR("Couldn't disable DPLL0\n"); + /* + * DMC assumes ownership of LCPLL and will get confused if we touch it. + */ + if (dev_priv->csr.dmc_payload) { + /* disable DPLL0 */ + I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & + ~LCPLL_PLL_ENABLE); + if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1)) + DRM_ERROR("Couldn't disable DPLL0\n"); + } intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS); } From 08aef7caa14f1c0b7c5d79d61d279bcedc188ab9 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 26 Aug 2015 01:36:09 +0530 Subject: [PATCH 009/134] drm/i915/skl: Block disable call for pw1 if dmc firmware is present. Another interesting criteria to work dmc as expected is pw1 to be enabled by driver and dmc will shut it off in its execution sequence. If already disabled by driver dmc will get confuse and behave differently than expected found during pc10 entry issue for skl. So berfore we disable power-well 1, added check if dmc firmware is present and driver will not disable power well 1, but for any reason if firmware is not present of failed to load we can shut off the power well 1 which will save some power. As skl is currently fully dependent on dmc to go in lowest possible power state (dc6) but the same is not applicable for bxt. Display engine can enter into dc9 without dmc, hence unblocking disable call. v1: Initial version. v2: Rebased as per current patch series. Cc: Daniel Vetter Cc: Damien Lespiau Cc: Imre Deak Cc: Sunil Kamath Signed-off-by: Animesh Manna Signed-off-by: Vathsala Nagaraju Reviewed-by: A.Sunil Kamath Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 85c35fdfac65..4a815bb6cfca 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -656,9 +656,15 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, } } else { if (enable_requested) { - I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask); - POSTING_READ(HSW_PWR_WELL_DRIVER); - DRM_DEBUG_KMS("Disabling %s\n", power_well->name); + if (IS_SKYLAKE(dev) && + (power_well->data == SKL_DISP_PW_1) && + (intel_csr_load_status_get(dev_priv) == FW_LOADED)) + DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n"); + else { + I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask); + POSTING_READ(HSW_PWR_WELL_DRIVER); + DRM_DEBUG_KMS("Disabling %s\n", power_well->name); + } if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) && power_well->data == SKL_DISP_PW_2) { From 28694070d849c98290288734ef67a3ef484425ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 13:40:44 +0300 Subject: [PATCH 010/134] drm/i915: Use intel_panel for DVO fixed mode handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace intel_dvo->panel_fixed_mode with the appropriate intel_panel stuff. Now all connectors that have a fixed mode use intel_panel. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kahola Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dvo.c | 49 ++++++++++++++------------------ 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index c80fe1f49ede..0bc8aa8b81c7 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -97,7 +97,8 @@ struct intel_dvo { struct intel_dvo_device dev; - struct drm_display_mode *panel_fixed_mode; + struct intel_connector *attached_connector; + bool panel_wants_dither; }; @@ -201,6 +202,8 @@ intel_dvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); + const struct drm_display_mode *fixed_mode = + to_intel_connector(connector)->panel.fixed_mode; int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; int target_clock = mode->clock; @@ -209,13 +212,13 @@ intel_dvo_mode_valid(struct drm_connector *connector, /* XXX: Validate clock range */ - if (intel_dvo->panel_fixed_mode) { - if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay) + if (fixed_mode) { + if (mode->hdisplay > fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay) + if (mode->vdisplay > fixed_mode->vdisplay) return MODE_PANEL; - target_clock = intel_dvo->panel_fixed_mode->clock; + target_clock = fixed_mode->clock; } if (target_clock > max_dotclk) @@ -228,6 +231,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { struct intel_dvo *intel_dvo = enc_to_dvo(encoder); + const struct drm_display_mode *fixed_mode = + intel_dvo->attached_connector->panel.fixed_mode; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; /* If we have timings from the BIOS for the panel, put them in @@ -235,21 +240,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - if (intel_dvo->panel_fixed_mode != NULL) { -#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x - C(hdisplay); - C(hsync_start); - C(hsync_end); - C(htotal); - C(vdisplay); - C(vsync_start); - C(vsync_end); - C(vtotal); - C(clock); -#undef C - - drm_mode_set_crtcinfo(adjusted_mode, 0); - } + if (fixed_mode) + intel_fixed_panel_mode(fixed_mode, adjusted_mode); return true; } @@ -318,8 +310,9 @@ intel_dvo_detect(struct drm_connector *connector, bool force) static int intel_dvo_get_modes(struct drm_connector *connector) { - struct intel_dvo *intel_dvo = intel_attached_dvo(connector); struct drm_i915_private *dev_priv = connector->dev->dev_private; + const struct drm_display_mode *fixed_mode = + to_intel_connector(connector)->panel.fixed_mode; /* We should probably have an i2c driver get_modes function for those * devices which will have a fixed set of modes determined by the chip @@ -331,9 +324,9 @@ static int intel_dvo_get_modes(struct drm_connector *connector) if (!list_empty(&connector->probed_modes)) return 1; - if (intel_dvo->panel_fixed_mode != NULL) { + if (fixed_mode) { struct drm_display_mode *mode; - mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode); + mode = drm_mode_duplicate(connector->dev, fixed_mode); if (mode) { drm_mode_probed_add(connector, mode); return 1; @@ -346,6 +339,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector) static void intel_dvo_destroy(struct drm_connector *connector) { drm_connector_cleanup(connector); + intel_panel_fini(&to_intel_connector(connector)->panel); kfree(connector); } @@ -372,8 +366,6 @@ static void intel_dvo_enc_destroy(struct drm_encoder *encoder) if (intel_dvo->dev.dev_ops->destroy) intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev); - kfree(intel_dvo->panel_fixed_mode); - intel_encoder_destroy(encoder); } @@ -438,6 +430,8 @@ void intel_dvo_init(struct drm_device *dev) return; } + intel_dvo->attached_connector = intel_connector; + intel_encoder = &intel_dvo->base; drm_encoder_init(dev, &intel_encoder->base, &intel_dvo_enc_funcs, encoder_type); @@ -542,8 +536,9 @@ void intel_dvo_init(struct drm_device *dev) * headers, likely), so for now, just get the current * mode being output through DVO. */ - intel_dvo->panel_fixed_mode = - intel_dvo_get_current_mode(connector); + intel_panel_init(&intel_connector->panel, + intel_dvo_get_current_mode(connector), + NULL); intel_dvo->panel_wants_dither = true; } From 124abe076fd8b360dd7c651046cb8b204268efeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 13:40:45 +0300 Subject: [PATCH 011/134] drm/i915: Always call the adjusted mode 'adjusted_mode' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always name any variable pointing at the adjusted mode as 'adjustead_mode'. This will make it much easier to identify when we should use the crtc_ timings and when we shoudln't. Conversion was performed with coccinelle: @@ expression E; identifier I; @@ - struct drm_display_mode *I = &E.adjusted_mode; + struct drm_display_mode *adjusted_mode = &E.adjusted_mode; <... - I + adjusted_mode ...> Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kahola [danvet: Fixup conflicts.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 7 ++++--- drivers/gpu/drm/i915/intel_display.c | 12 +++++------- drivers/gpu/drm/i915/intel_dsi.c | 13 ++++++------- drivers/gpu/drm/i915/intel_hdmi.c | 9 +++------ drivers/gpu/drm/i915/intel_lvds.c | 3 +-- drivers/gpu/drm/i915/intel_pm.c | 14 ++++++-------- drivers/gpu/drm/i915/intel_sdvo.c | 3 +-- drivers/gpu/drm/i915/intel_sprite.c | 8 ++++---- 8 files changed, 30 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index e35997ebb331..d9876c55fd6f 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -396,7 +396,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); - struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; struct drm_connector *connector; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -419,10 +419,11 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) connector->eld[5] |= (1 << 2); - connector->eld[6] = drm_av_sync_delay(connector, mode) / 2; + connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2; if (dev_priv->display.audio_codec_enable) - dev_priv->display.audio_codec_enable(connector, intel_encoder, mode); + dev_priv->display.audio_codec_enable(connector, intel_encoder, + adjusted_mode); if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5d8645ee3294..45ec0b8bf43a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4392,8 +4392,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, int skl_update_scaler_crtc(struct intel_crtc_state *state) { struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); - struct drm_display_mode *adjusted_mode = - &state->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode; DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); @@ -7625,8 +7624,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - struct drm_display_mode *adjusted_mode = - &intel_crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; uint32_t crtc_vtotal, crtc_vblank_end; int vsyncshift = 0; @@ -12821,11 +12819,11 @@ static void update_scanline_offset(struct intel_crtc *crtc) * one to the value. */ if (IS_GEN2(dev)) { - const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; int vtotal; - vtotal = mode->crtc_vtotal; - if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vtotal = adjusted_mode->crtc_vtotal; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) vtotal /= 2; crtc->scanline_offset = vtotal - 1; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 61d69c214508..23b7fc517e96 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -774,8 +774,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; enum port port; unsigned int bpp = intel_crtc->config->pipe_bpp; u32 val, tmp; @@ -880,14 +879,14 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) intel_dsi->video_mode_format == VIDEO_MODE_BURST) { I915_WRITE(MIPI_HS_TX_TIMEOUT(port), txbyteclkhs(adjusted_mode->htotal, bpp, - intel_dsi->lane_count, - intel_dsi->burst_mode_ratio) + 1); + intel_dsi->lane_count, + intel_dsi->burst_mode_ratio) + 1); } else { I915_WRITE(MIPI_HS_TX_TIMEOUT(port), txbyteclkhs(adjusted_mode->vtotal * - adjusted_mode->htotal, - bpp, intel_dsi->lane_count, - intel_dsi->burst_mode_ratio) + 1); + adjusted_mode->htotal, + bpp, intel_dsi->lane_count, + intel_dsi->burst_mode_ratio) + 1); } I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout); I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port), diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index bb33c66b0b12..c11703a0e6b1 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1537,8 +1537,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; intel_hdmi_prepare(encoder); @@ -1555,8 +1554,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; u32 val; @@ -1822,8 +1820,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; enum dpio_channel ch = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; int data, i, stagger; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2c2d1f0737c8..5e70acf944c3 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -139,8 +139,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - const struct drm_display_mode *adjusted_mode = - &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; int pipe = crtc->pipe; u32 temp; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ab5ac5ee1825..d5c60bbb9c4c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1502,8 +1502,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) if (crtc) { /* self-refresh has much higher latency */ static const int sr_latency_ns = 12000; - const struct drm_display_mode *adjusted_mode = - &to_intel_crtc(crtc)->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode; int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->crtc_htotal; int hdisplay = to_intel_crtc(crtc)->config->pipe_src_w; @@ -1650,8 +1649,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) if (HAS_FW_BLC(dev) && enabled) { /* self-refresh has much higher latency */ static const int sr_latency_ns = 6000; - const struct drm_display_mode *adjusted_mode = - &to_intel_crtc(enabled)->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &to_intel_crtc(enabled)->config->base.adjusted_mode; int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->crtc_htotal; int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w; @@ -2088,7 +2086,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; u32 linetime, ips_linetime; if (!intel_crtc->active) @@ -2097,9 +2095,9 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) /* The WM are computed with base on how long it takes to fill a single * row at the given clock rate, multiplied by 8. * */ - linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8, - mode->crtc_clock); - ips_linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8, + linetime = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8, + adjusted_mode->crtc_clock); + ips_linetime = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8, dev_priv->cdclk_freq); return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) | diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 05521b5c6878..b0b96fded708 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1189,8 +1189,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder) struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc); - struct drm_display_mode *adjusted_mode = - &crtc->config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; struct drm_display_mode *mode = &crtc->config->base.mode; struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); u32 sdvox; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 4349fde4b72c..821804071d91 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -79,19 +79,19 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) void intel_pipe_update_start(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; - const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; enum pipe pipe = crtc->pipe; long timeout = msecs_to_jiffies_timeout(1); int scanline, min, max, vblank_start; wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); DEFINE_WAIT(wait); - vblank_start = mode->crtc_vblank_start; - if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = adjusted_mode->crtc_vblank_start; + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) vblank_start = DIV_ROUND_UP(vblank_start, 2); /* FIXME needs to be calibrated sensibly */ - min = vblank_start - usecs_to_scanlines(mode, 100); + min = vblank_start - usecs_to_scanlines(adjusted_mode, 100); max = vblank_start - 1; local_irq_disable(); From 0d44d3fa2b9089b0039118351773d465204ad581 Mon Sep 17 00:00:00 2001 From: Alex Dai Date: Tue, 22 Sep 2015 13:48:40 -0700 Subject: [PATCH 012/134] drm/i915/guc: Fix a bug in GuC status check Bit 16 of GuC status indicates resuming from RC6. The LAPIC_DONE status is a reliable readiness flag only when resuming from RC6. This fix a racing issue that allocation of doorbell fails whilst GuC init is not finished. Signed-off-by: Alex Dai Reviewed-by: Sagar Arun Kamble Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_guc_reg.h | 1 + drivers/gpu/drm/i915/intel_guc_loader.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h index 9d79a6b7cc2f..b35566164c4d 100644 --- a/drivers/gpu/drm/i915/i915_guc_reg.h +++ b/drivers/gpu/drm/i915/i915_guc_reg.h @@ -37,6 +37,7 @@ #define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT) #define GS_MIA_SHIFT 16 #define GS_MIA_MASK (0x07 << GS_MIA_SHIFT) +#define GS_MIA_CORE_STATE (1 << GS_MIA_SHIFT) #define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index e0601cc5a795..40241f37e24b 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -209,9 +209,10 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv, u32 *status) { u32 val = I915_READ(GUC_STATUS); + u32 uk_val = val & GS_UKERNEL_MASK; *status = val; - return ((val & GS_UKERNEL_MASK) == GS_UKERNEL_READY || - (val & GS_UKERNEL_MASK) == GS_UKERNEL_LAPIC_DONE); + return (uk_val == GS_UKERNEL_READY || + ((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE)); } /* From 165ed87c47ae7dd0deab53d552a29d7985569c28 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 23 Sep 2015 14:37:17 -0700 Subject: [PATCH 013/134] drm/i915: fixup runtime PM handling v2 According to the PCI docs and Rafael, we don't need to be doing explicit enables and disables in our init and teardown routines, as they're taken care of by the PCI core. So drop the pm_runtime_disable() at teardown and pm_runtime_set_active() at init. This fixes one failure of the basic-pci-d3-state test on my BYT. v2: drop extra get_noresume() and put_noidle() (Rafael) Signed-off-by: Jesse Barnes Cc: "Rafael J. Wysocki" Acked-by: "Rafael J. Wysocki" Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 4a815bb6cfca..e1fdbabaf2bf 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1828,7 +1828,6 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv) /* Make sure we're not suspended first. */ pm_runtime_get_sync(device); - pm_runtime_disable(device); } /** @@ -2120,8 +2119,6 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) if (!HAS_RUNTIME_PM(dev)) return; - pm_runtime_set_active(device); - /* * RPM depends on RC6 to save restore the GT HW context, so make RC6 a * requirement. From d9d7000d5a4dfda6aa54907b96cfa490f4140aa9 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 24 Sep 2015 10:24:56 +0530 Subject: [PATCH 014/134] drm/i915/bxt: eDP low vswing support Adding voltage swing table for edp to support low vswings. v2: Rebased. Signed-off-by: Sonika Jindal Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9e640eafc50d..205f61832d4a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -256,9 +256,6 @@ struct bxt_ddi_buf_trans { bool default_index; /* true if the entry represents default value */ }; -/* BSpec does not define separate vswing/pre-emphasis values for eDP. - * Using DP values for eDP as well. - */ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { /* Idx NT mV diff db */ { 52, 0x9A, 0, 128, true }, /* 0: 400 0 */ @@ -273,6 +270,20 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ }; +static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = { + /* Idx NT mV diff db */ + { 26, 0, 0, 128, false }, /* 0: 200 0 */ + { 38, 0, 0, 112, false }, /* 1: 200 1.5 */ + { 48, 0, 0, 96, false }, /* 2: 200 4 */ + { 54, 0, 0, 69, false }, /* 3: 200 6 */ + { 32, 0, 0, 128, false }, /* 4: 250 0 */ + { 48, 0, 0, 104, false }, /* 5: 250 1.5 */ + { 54, 0, 0, 85, false }, /* 6: 250 4 */ + { 43, 0, 0, 128, false }, /* 7: 300 0 */ + { 54, 0, 0, 101, false }, /* 8: 300 1.5 */ + { 48, 0, 0, 128, false }, /* 9: 300 0 */ +}; + /* BSpec has 2 recommended values - entries 0 and 8. * Using the entry with higher vswing. */ @@ -2112,7 +2123,11 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, u32 n_entries, i; uint32_t val; - if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { + if (type == INTEL_OUTPUT_EDP && dev_priv->edp_low_vswing) { + n_entries = ARRAY_SIZE(bxt_ddi_translations_edp); + ddi_translations = bxt_ddi_translations_edp; + } else if (type == INTEL_OUTPUT_DISPLAYPORT + || type == INTEL_OUTPUT_EDP) { n_entries = ARRAY_SIZE(bxt_ddi_translations_dp); ddi_translations = bxt_ddi_translations_dp; } else if (type == INTEL_OUTPUT_HDMI) { From 9c58a049566566a8dc5aa1874ddfb3d32f954260 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 24 Sep 2015 10:22:54 +0530 Subject: [PATCH 015/134] drm/i915/bxt: Set oscaledcompmethod to enable scale value Bspec update tells that we have to enable oscaledcompmethod instead of ouniqetrangenmethod for enabling scale value during swing programming. v2: Adding back 'don't care' values to bxt_ddi_translations_dp and add error message if ouniquetrangemethod was set (Imre) Signed-off-by: Sonika Jindal Reviewed-by: Sivakumar Thulasimani (v1) Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 56157eb8719b..184b1237a868 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1395,7 +1395,8 @@ enum skl_disp_power_wells { #define BXT_PORT_TX_DW3_LN0(port) _PORT3(port, _PORT_TX_DW3_LN0_A, \ _PORT_TX_DW3_LN0_B, \ _PORT_TX_DW3_LN0_C) -#define UNIQE_TRANGE_EN_METHOD (1 << 27) +#define SCALE_DCOMP_METHOD (1 << 26) +#define UNIQUE_TRANGE_EN_METHOD (1 << 27) #define _PORT_TX_DW4_LN0_A 0x162510 #define _PORT_TX_DW4_LN0_B 0x6C510 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 205f61832d4a..0e46679fde5a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2165,9 +2165,13 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val); val = I915_READ(BXT_PORT_TX_DW3_LN0(port)); - val &= ~UNIQE_TRANGE_EN_METHOD; + val &= ~SCALE_DCOMP_METHOD; if (ddi_translations[level].enable) - val |= UNIQE_TRANGE_EN_METHOD; + val |= SCALE_DCOMP_METHOD; + + if ((val & UNIQUE_TRANGE_EN_METHOD) && !(val & SCALE_DCOMP_METHOD)) + DRM_ERROR("Disabled scaling while ouniqetrangenmethod was set"); + I915_WRITE(BXT_PORT_TX_DW3_GRP(port), val); val = I915_READ(BXT_PORT_TX_DW4_LN0(port)); From eecf613a432c663d206a11c2543e9cca2ddc3aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 21 Sep 2015 18:05:14 +0300 Subject: [PATCH 016/134] drm/i915: Parametrize fence registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Hide the 945 vs. rest of gen2/3 difference in the macro Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_fence.c | 41 ++++++++++++--------------- drivers/gpu/drm/i915/i915_gpu_error.c | 21 ++++++-------- drivers/gpu/drm/i915/i915_reg.h | 18 ++++++++---- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index 6077dffb318a..1cbfd5b83135 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -59,19 +59,19 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = dev->dev_private; - int fence_reg; + int fence_reg_lo, fence_reg_hi; int fence_pitch_shift; if (INTEL_INFO(dev)->gen >= 6) { - fence_reg = FENCE_REG_SANDYBRIDGE_0; - fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + fence_reg_lo = FENCE_REG_GEN6_LO(reg); + fence_reg_hi = FENCE_REG_GEN6_HI(reg); + fence_pitch_shift = GEN6_FENCE_PITCH_SHIFT; } else { - fence_reg = FENCE_REG_965_0; + fence_reg_lo = FENCE_REG_965_LO(reg); + fence_reg_hi = FENCE_REG_965_HI(reg); fence_pitch_shift = I965_FENCE_PITCH_SHIFT; } - fence_reg += reg * 8; - /* To w/a incoherency with non-atomic 64-bit register updates, * we split the 64-bit update into two 32-bit writes. In order * for a partial fence not to be evaluated between writes, we @@ -81,8 +81,8 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, * For extra levels of paranoia, we make sure each step lands * before applying the next step. */ - I915_WRITE(fence_reg, 0); - POSTING_READ(fence_reg); + I915_WRITE(fence_reg_lo, 0); + POSTING_READ(fence_reg_lo); if (obj) { u32 size = i915_gem_obj_ggtt_size(obj); @@ -103,14 +103,14 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; - I915_WRITE(fence_reg + 4, val >> 32); - POSTING_READ(fence_reg + 4); + I915_WRITE(fence_reg_hi, val >> 32); + POSTING_READ(fence_reg_hi); - I915_WRITE(fence_reg + 0, val); - POSTING_READ(fence_reg); + I915_WRITE(fence_reg_lo, val); + POSTING_READ(fence_reg_lo); } else { - I915_WRITE(fence_reg + 4, 0); - POSTING_READ(fence_reg + 4); + I915_WRITE(fence_reg_hi, 0); + POSTING_READ(fence_reg_hi); } } @@ -149,13 +149,8 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg, } else val = 0; - if (reg < 8) - reg = FENCE_REG_830_0 + reg * 4; - else - reg = FENCE_REG_945_8 + (reg - 8) * 4; - - I915_WRITE(reg, val); - POSTING_READ(reg); + I915_WRITE(FENCE_REG(reg), val); + POSTING_READ(FENCE_REG(reg)); } static void i830_write_fence_reg(struct drm_device *dev, int reg, @@ -186,8 +181,8 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg, } else val = 0; - I915_WRITE(FENCE_REG_830_0 + reg * 4, val); - POSTING_READ(FENCE_REG_830_0 + reg * 4); + I915_WRITE(FENCE_REG(reg), val); + POSTING_READ(FENCE_REG(reg)); } inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index f95de05f793d..d979dca1491a 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -792,20 +792,15 @@ static void i915_gem_record_fences(struct drm_device *dev, int i; if (IS_GEN3(dev) || IS_GEN2(dev)) { - for (i = 0; i < 8; i++) - error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - error->fence[i+8] = I915_READ(FENCE_REG_945_8 + - (i * 4)); - } else if (IS_GEN5(dev) || IS_GEN4(dev)) - for (i = 0; i < 16; i++) - error->fence[i] = I915_READ64(FENCE_REG_965_0 + - (i * 8)); - else if (INTEL_INFO(dev)->gen >= 6) for (i = 0; i < dev_priv->num_fence_regs; i++) - error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + - (i * 8)); + error->fence[i] = I915_READ(FENCE_REG(i)); + } else if (IS_GEN5(dev) || IS_GEN4(dev)) { + for (i = 0; i < dev_priv->num_fence_regs; i++) + error->fence[i] = I915_READ64(FENCE_REG_965_LO(i)); + } else if (INTEL_INFO(dev)->gen >= 6) { + for (i = 0; i < dev_priv->num_fence_regs; i++) + error->fence[i] = I915_READ64(FENCE_REG_GEN6_LO(i)); + } } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 184b1237a868..d5a07906721f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1437,9 +1437,15 @@ enum skl_disp_power_wells { /* * Fence registers + * [0-7] @ 0x2000 gen2,gen3 + * [8-15] @ 0x3000 945,g33,pnv + * + * [0-15] @ 0x3000 gen4,gen5 + * + * [0-15] @ 0x100000 gen6,vlv,chv + * [0-31] @ 0x100000 gen7+ */ -#define FENCE_REG_830_0 0x2000 -#define FENCE_REG_945_8 0x3000 +#define FENCE_REG(i) (0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4) #define I830_FENCE_START_MASK 0x07f80000 #define I830_FENCE_TILING_Y_SHIFT 12 #define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) @@ -1452,14 +1458,16 @@ enum skl_disp_power_wells { #define I915_FENCE_START_MASK 0x0ff00000 #define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) -#define FENCE_REG_965_0 0x03000 +#define FENCE_REG_965_LO(i) (0x03000 + (i) * 8) +#define FENCE_REG_965_HI(i) (0x03000 + (i) * 8 + 4) #define I965_FENCE_PITCH_SHIFT 2 #define I965_FENCE_TILING_Y_SHIFT 1 #define I965_FENCE_REG_VALID (1<<0) #define I965_FENCE_MAX_PITCH_VAL 0x0400 -#define FENCE_REG_SANDYBRIDGE_0 0x100000 -#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32 +#define FENCE_REG_GEN6_LO(i) (0x100000 + (i) * 8) +#define FENCE_REG_GEN6_HI(i) (0x100000 + (i) * 8 + 4) +#define GEN6_FENCE_PITCH_SHIFT 32 #define GEN7_FENCE_MAX_PITCH_VAL 0x0800 From b26d3ea323b41a56db74f46131bc89e3c485f365 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 23 Sep 2015 16:11:41 +0200 Subject: [PATCH 017/134] drm/i915: Add primary plane to mask if it's visible This fixes the warnings like "plane A assertion failure, should be disabled but not" that on the initial modeset during boot. This can happen if the primary plane is enabled by the firmware, but inheriting it fails because the DMAR is active or for other reasons. Most likely caused by commit 36750f284b3a4f19b304fda1bb7d6e9e1275ea8d Author: Maarten Lankhorst Date: Mon Jun 1 12:49:54 2015 +0200 drm/i915: update plane state during init This is the 4.4 version of commit 721a09f7393de6c28a07516dccd654c6e995944a Author: Maarten Lankhorst Date: Tue Sep 15 14:28:54 2015 +0200 drm/i915: Add primary plane to mask if it's visible Reported-by: Andreas Reis Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91429 Reported-and-tested-by: Emil Renner Berthing Tested-by: Andreas Reis Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 45ec0b8bf43a..036c704f3067 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15128,11 +15128,15 @@ static bool primary_get_hw_state(struct intel_plane *plane) /* FIXME read out full plane state for all planes */ static void readout_plane_state(struct intel_crtc *crtc) { + struct drm_plane *primary = crtc->base.primary; struct intel_plane_state *plane_state = - to_intel_plane_state(crtc->base.primary->state); + to_intel_plane_state(primary->state); plane_state->visible = - primary_get_hw_state(to_intel_plane(crtc->base.primary)); + primary_get_hw_state(to_intel_plane(primary)); + + if (plane_state->visible) + crtc->base.state->plane_mask |= 1 << drm_plane_index(primary); } static void intel_modeset_readout_hw_state(struct drm_device *dev) From 1ca36d4cb3436bd783f8688b563830341a8d9150 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 23 Sep 2015 12:52:22 -0300 Subject: [PATCH 018/134] drm/i915: don't use the first stolen page on Broadwell The spec says we just can't use it. v2: - Add WA name (Ville). - Add a big comment explaining that we still didn't fix the problem where we inherit a framebuffer on the first page (Chris, Ville). Signed-off-by: Paulo Zanoni Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 15207796e1b3..69eebc678f01 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -51,6 +51,11 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv, if (!drm_mm_initialized(&dev_priv->mm.stolen)) return -ENODEV; + /* See the comment at the drm_mm_init() call for more about this check. + * WaSkipStolenMemoryFirstPage:bdw,chv (incomplete) */ + if (INTEL_INFO(dev_priv)->gen == 8 && start < 4096) + start = 4096; + mutex_lock(&dev_priv->mm.stolen_lock); ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, size, alignment, start, end, @@ -393,7 +398,17 @@ int i915_gem_init_stolen(struct drm_device *dev) dev_priv->gtt.stolen_usable_size = dev_priv->gtt.stolen_size - reserved_total; - /* Basic memrange allocator for stolen space */ + /* + * Basic memrange allocator for stolen space. + * + * TODO: Notice that some platforms require us to not use the first page + * of the stolen memory but their BIOSes may still put the framebuffer + * on the first page. So we don't reserve this page for now because of + * that. Our current solution is to just prevent new nodes from being + * inserted on the first page - see the check we have at + * i915_gem_stolen_insert_node_in_range(). We may want to fix the fbcon + * problem later. + */ drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_usable_size); return 0; From 9f218336bd44719c64a6e7df142b101304452692 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 23 Sep 2015 12:52:27 -0300 Subject: [PATCH 019/134] drm/i915: extract fbc_supported() Make it clear that we're checking whether FBC is supported or not. The fact that the vfunc is not NULL is just a consequence. Another name option would have been fbc_initialized(). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 6777fbb25d07..20ab1b42dc7e 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -41,6 +41,11 @@ #include "intel_drv.h" #include "i915_drv.h" +static inline bool fbc_supported(struct drm_i915_private *dev_priv) +{ + return dev_priv->fbc.enable_fbc != NULL; +} + /* * In some platforms where the CRTC's x:0/y:0 coordinates doesn't match the * frontbuffer's x:0/y:0 coordinates we lie to the hardware about the plane's @@ -439,7 +444,7 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) */ void intel_fbc_disable(struct drm_i915_private *dev_priv) { - if (!dev_priv->fbc.enable_fbc) + if (!fbc_supported(dev_priv)) return; mutex_lock(&dev_priv->fbc.lock); @@ -457,7 +462,7 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!dev_priv->fbc.enable_fbc) + if (!fbc_supported(dev_priv)) return; mutex_lock(&dev_priv->fbc.lock); @@ -685,7 +690,7 @@ static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { - if (!dev_priv->fbc.enable_fbc) + if (!fbc_supported(dev_priv)) return; mutex_lock(&dev_priv->fbc.lock); @@ -948,7 +953,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) */ void intel_fbc_update(struct drm_i915_private *dev_priv) { - if (!dev_priv->fbc.enable_fbc) + if (!fbc_supported(dev_priv)) return; mutex_lock(&dev_priv->fbc.lock); @@ -962,7 +967,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, { unsigned int fbc_bits; - if (!dev_priv->fbc.enable_fbc) + if (!fbc_supported(dev_priv)) return; if (origin == ORIGIN_GTT) @@ -989,7 +994,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { - if (!dev_priv->fbc.enable_fbc) + if (!fbc_supported(dev_priv)) return; if (origin == ORIGIN_GTT) From 3c5f174e383d6eddd9190637cebd005174287996 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 23 Sep 2015 12:52:24 -0300 Subject: [PATCH 020/134] drm/i915: export size_is_valid() from __intel_fbc_update() Make the giant function a little less giant. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson [danvet: Add pipe_ prefix as suggested by Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 35 ++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 20ab1b42dc7e..1b2ebb2c1f53 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -754,6 +754,26 @@ static bool pixel_format_is_valid(struct drm_framebuffer *fb) } } +static bool pipe_size_is_valid(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + unsigned int max_w, max_h; + + if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { + max_w = 4096; + max_h = 4096; + } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) { + max_w = 4096; + max_h = 2048; + } else { + max_w = 2048; + max_h = 1536; + } + + return crtc->config->pipe_src_w <= max_w && + crtc->config->pipe_src_h <= max_h; +} + /** * __intel_fbc_update - enable/disable FBC as needed, unlocked * @dev_priv: i915 device instance @@ -780,7 +800,6 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; const struct drm_display_mode *adjusted_mode; - unsigned int max_width, max_height; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); @@ -829,21 +848,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) goto out_disable; } - if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { - max_width = 4096; - max_height = 4096; - } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) { - max_width = 4096; - max_height = 2048; - } else { - max_width = 2048; - max_height = 1536; - } - if (intel_crtc->config->pipe_src_w > max_width || - intel_crtc->config->pipe_src_h > max_height) { + if (!pipe_size_is_valid(intel_crtc)) { set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); goto out_disable; } + if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) && intel_crtc->plane != PLANE_A) { set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); From 5e7234c9ccf88c427448fbe147839b4dca82efde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Sep 2015 16:37:43 +0300 Subject: [PATCH 021/134] drm/i915: s/mode/adjusted_mode/ in functions that really get passed the adjusted_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the function argument to 'adjusted_mode' whenever the function only ever gets passed the adjusted_mode. v2: Update due to intel_dsi.c changes Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kahola Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_audio.c | 17 +++++++------- drivers/gpu/drm/i915/intel_dsi.c | 22 +++++++++--------- drivers/gpu/drm/i915/intel_panel.c | 36 ++++++++++++++--------------- drivers/gpu/drm/i915/intel_sdvo.c | 6 ++--- drivers/gpu/drm/i915/intel_sprite.c | 8 ++++--- 6 files changed, 47 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 04d710ff4913..ad37b2591878 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -646,7 +646,7 @@ struct drm_i915_display_funcs { void (*crtc_disable)(struct drm_crtc *crtc); void (*audio_codec_enable)(struct drm_connector *connector, struct intel_encoder *encoder, - struct drm_display_mode *mode); + const struct drm_display_mode *adjusted_mode); void (*audio_codec_disable)(struct intel_encoder *encoder); void (*fdi_link_train)(struct drm_crtc *crtc); void (*init_clock_gating)(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index d9876c55fd6f..779f90c1ce69 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -69,17 +69,18 @@ static const struct { }; /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ -static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) +static u32 audio_config_hdmi_pixel_clock(const struct drm_display_mode *adjusted_mode) { int i; for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) { - if (mode->clock == hdmi_audio_clock[i].clock) + if (adjusted_mode->clock == hdmi_audio_clock[i].clock) break; } if (i == ARRAY_SIZE(hdmi_audio_clock)) { - DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", mode->clock); + DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", + adjusted_mode->clock); i = 1; } @@ -138,7 +139,7 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder) static void g4x_audio_codec_enable(struct drm_connector *connector, struct intel_encoder *encoder, - struct drm_display_mode *mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; @@ -203,7 +204,7 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder) static void hsw_audio_codec_enable(struct drm_connector *connector, struct intel_encoder *encoder, - struct drm_display_mode *mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); @@ -251,7 +252,7 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) tmp |= AUD_CONFIG_N_VALUE_INDEX; else - tmp |= audio_config_hdmi_pixel_clock(mode); + tmp |= audio_config_hdmi_pixel_clock(adjusted_mode); I915_WRITE(HSW_AUD_CFG(pipe), tmp); } @@ -304,7 +305,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder) static void ilk_audio_codec_enable(struct drm_connector *connector, struct intel_encoder *encoder, - struct drm_display_mode *mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); @@ -381,7 +382,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) tmp |= AUD_CONFIG_N_VALUE_INDEX; else - tmp |= audio_config_hdmi_pixel_clock(mode); + tmp |= audio_config_hdmi_pixel_clock(adjusted_mode); I915_WRITE(aud_config, tmp); } diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 23b7fc517e96..b4d5213f0abb 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -698,7 +698,7 @@ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, } static void set_dsi_timings(struct drm_encoder *encoder, - const struct drm_display_mode *mode) + const struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -710,10 +710,10 @@ static void set_dsi_timings(struct drm_encoder *encoder, u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp; - hactive = mode->hdisplay; - hfp = mode->hsync_start - mode->hdisplay; - hsync = mode->hsync_end - mode->hsync_start; - hbp = mode->htotal - mode->hsync_end; + hactive = adjusted_mode->hdisplay; + hfp = adjusted_mode->hsync_start - adjusted_mode->hdisplay; + hsync = adjusted_mode->hsync_end - adjusted_mode->hsync_start; + hbp = adjusted_mode->htotal - adjusted_mode->hsync_end; if (intel_dsi->dual_link) { hactive /= 2; @@ -724,9 +724,9 @@ static void set_dsi_timings(struct drm_encoder *encoder, hbp /= 2; } - vfp = mode->vsync_start - mode->vdisplay; - vsync = mode->vsync_end - mode->vsync_start; - vbp = mode->vtotal - mode->vsync_end; + vfp = adjusted_mode->vsync_start - adjusted_mode->vdisplay; + vsync = adjusted_mode->vsync_end - adjusted_mode->vsync_start; + vbp = adjusted_mode->vtotal - adjusted_mode->vsync_end; /* horizontal values are in terms of high speed byte clock */ hactive = txbyteclkhs(hactive, bpp, lane_count, @@ -745,11 +745,11 @@ static void set_dsi_timings(struct drm_encoder *encoder, * whereas these values should be based on resolution. */ I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port), - mode->hdisplay); + adjusted_mode->hdisplay); I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port), - mode->vdisplay); + adjusted_mode->vdisplay); I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port), - mode->vtotal); + adjusted_mode->vtotal); } I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 2c11b4eedfc6..4294f605fe00 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -172,46 +172,46 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, } static void -centre_horizontally(struct drm_display_mode *mode, +centre_horizontally(struct drm_display_mode *adjusted_mode, int width) { u32 border, sync_pos, blank_width, sync_width; /* keep the hsync and hblank widths constant */ - sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; - blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; + sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; sync_pos = (blank_width - sync_width + 1) / 2; - border = (mode->hdisplay - width + 1) / 2; + border = (adjusted_mode->hdisplay - width + 1) / 2; border += border & 1; /* make the border even */ - mode->crtc_hdisplay = width; - mode->crtc_hblank_start = width + border; - mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; + adjusted_mode->crtc_hdisplay = width; + adjusted_mode->crtc_hblank_start = width + border; + adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width; - mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; - mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width; } static void -centre_vertically(struct drm_display_mode *mode, +centre_vertically(struct drm_display_mode *adjusted_mode, int height) { u32 border, sync_pos, blank_width, sync_width; /* keep the vsync and vblank widths constant */ - sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; - blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; + sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start; sync_pos = (blank_width - sync_width + 1) / 2; - border = (mode->vdisplay - height + 1) / 2; + border = (adjusted_mode->vdisplay - height + 1) / 2; - mode->crtc_vdisplay = height; - mode->crtc_vblank_start = height + border; - mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; + adjusted_mode->crtc_vdisplay = height; + adjusted_mode->crtc_vblank_start = height + border; + adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width; - mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; - mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width; } static inline u32 panel_fitter_scaling(u32 source, u32 target) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index b0b96fded708..ab75b6146e84 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -603,11 +603,11 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, return false; } -static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) +static int intel_sdvo_get_pixel_multiplier(const struct drm_display_mode *adjusted_mode) { - if (mode->clock >= 100000) + if (adjusted_mode->clock >= 100000) return 1; - else if (mode->clock >= 50000) + else if (adjusted_mode->clock >= 50000) return 2; else return 4; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 821804071d91..b229c6752671 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -53,13 +53,15 @@ format_is_yuv(uint32_t format) } } -static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) +static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, + int usecs) { /* paranoia */ - if (!mode->crtc_htotal) + if (!adjusted_mode->crtc_htotal) return 1; - return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal); + return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, + 1000 * adjusted_mode->crtc_htotal); } /** From aad941d53f7aa2b642a798e6b3de520c19ba2e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Sep 2015 16:38:56 +0300 Subject: [PATCH 022/134] drm/i915: Always use crtc_ timings when dealing with adjustead_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The adjustead_mode crtc_ timings are what we will program into the hardware, so it's those timings we should be looking practically everywhere. The normal and crtc_ timings should differ only when stere doubling is used. In that case the normal timings are the orignal non-doubled timigns, and crtc_ timings are the doubled timings used by the hardware. The only case where we continue to look at the normal timings is when we pass the adjusted_mode to drm_match_{cea,hdmi}_mode() to find the VIC. drm_edid keeps the modes aronund in the non-double form only, so it needs the non-double timings to match against. Done with sed 's/adjusted_mode->\([vhVH]\)/adjusted_mode->crtc_\1/g' 's/adjusted_mode->clock/adjusted_mode->crtc_clock/g' with a manual s/VDisplay/vdisplay/ within the comment in intel_dvo.c v2: Update due to intel_dsi.c changes Reviewed-by: Mika Kahola Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo_ivch.c | 8 ++-- drivers/gpu/drm/i915/intel_audio.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_dp_mst.c | 2 +- drivers/gpu/drm/i915/intel_dsi.c | 30 +++++++------- drivers/gpu/drm/i915/intel_dvo.c | 8 ++-- drivers/gpu/drm/i915/intel_panel.c | 58 ++++++++++++++-------------- drivers/gpu/drm/i915/intel_sdvo.c | 4 +- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index 732ce8785945..e082f75317a0 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -414,16 +414,16 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | VR40_HORIZONTAL_INTERP_ENABLE); - if (mode->hdisplay != adjusted_mode->hdisplay || - mode->vdisplay != adjusted_mode->vdisplay) { + if (mode->hdisplay != adjusted_mode->crtc_hdisplay || + mode->vdisplay != adjusted_mode->crtc_vdisplay) { uint16_t x_ratio, y_ratio; vr01 |= VR01_PANEL_FIT_ENABLE; vr40 |= VR40_CLOCK_GATING_ENABLE; x_ratio = (((mode->hdisplay - 1) << 16) / - (adjusted_mode->hdisplay - 1)) >> 2; + (adjusted_mode->crtc_hdisplay - 1)) >> 2; y_ratio = (((mode->vdisplay - 1) << 16) / - (adjusted_mode->vdisplay - 1)) >> 2; + (adjusted_mode->crtc_vdisplay - 1)) >> 2; ivch_write(dvo, VR42, x_ratio); ivch_write(dvo, VR41, y_ratio); } else { diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 779f90c1ce69..e4c30e8c2674 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -74,13 +74,13 @@ static u32 audio_config_hdmi_pixel_clock(const struct drm_display_mode *adjusted int i; for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) { - if (adjusted_mode->clock == hdmi_audio_clock[i].clock) + if (adjusted_mode->crtc_clock == hdmi_audio_clock[i].clock) break; } if (i == ARRAY_SIZE(hdmi_audio_clock)) { DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", - adjusted_mode->clock); + adjusted_mode->crtc_clock); i = 1; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 036c704f3067..5105e09b65cc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4400,7 +4400,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state) return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX, &state->scaler_state.scaler_id, DRM_ROTATE_0, state->pipe_src_w, state->pipe_src_h, - adjusted_mode->hdisplay, adjusted_mode->vdisplay); + adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay); } /** @@ -6593,7 +6593,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. */ if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && - adjusted_mode->hsync_start == adjusted_mode->hdisplay) + adjusted_mode->crtc_hsync_start == adjusted_mode->crtc_hdisplay) return -EINVAL; if (HAS_IPS(dev)) diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index ff8ba55853be..cccf014d55c1 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -78,7 +78,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, return false; } - mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp); + mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); pipe_config->pbn = mst_pbn; slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b4d5213f0abb..4fb97c07bbc2 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -710,10 +710,10 @@ static void set_dsi_timings(struct drm_encoder *encoder, u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp; - hactive = adjusted_mode->hdisplay; - hfp = adjusted_mode->hsync_start - adjusted_mode->hdisplay; - hsync = adjusted_mode->hsync_end - adjusted_mode->hsync_start; - hbp = adjusted_mode->htotal - adjusted_mode->hsync_end; + hactive = adjusted_mode->crtc_hdisplay; + hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay; + hsync = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end; if (intel_dsi->dual_link) { hactive /= 2; @@ -724,9 +724,9 @@ static void set_dsi_timings(struct drm_encoder *encoder, hbp /= 2; } - vfp = adjusted_mode->vsync_start - adjusted_mode->vdisplay; - vsync = adjusted_mode->vsync_end - adjusted_mode->vsync_start; - vbp = adjusted_mode->vtotal - adjusted_mode->vsync_end; + vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay; + vsync = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end; /* horizontal values are in terms of high speed byte clock */ hactive = txbyteclkhs(hactive, bpp, lane_count, @@ -745,11 +745,11 @@ static void set_dsi_timings(struct drm_encoder *encoder, * whereas these values should be based on resolution. */ I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port), - adjusted_mode->hdisplay); + adjusted_mode->crtc_hdisplay); I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port), - adjusted_mode->vdisplay); + adjusted_mode->crtc_vdisplay); I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port), - adjusted_mode->vtotal); + adjusted_mode->crtc_vtotal); } I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive); @@ -782,7 +782,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe)); - mode_hdisplay = adjusted_mode->hdisplay; + mode_hdisplay = adjusted_mode->crtc_hdisplay; if (intel_dsi->dual_link) { mode_hdisplay /= 2; @@ -832,7 +832,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg); I915_WRITE(MIPI_DPI_RESOLUTION(port), - adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | + adjusted_mode->crtc_vdisplay << VERTICAL_ADDRESS_SHIFT | mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT); } @@ -878,13 +878,13 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) if (is_vid_mode(intel_dsi) && intel_dsi->video_mode_format == VIDEO_MODE_BURST) { I915_WRITE(MIPI_HS_TX_TIMEOUT(port), - txbyteclkhs(adjusted_mode->htotal, bpp, + txbyteclkhs(adjusted_mode->crtc_htotal, bpp, intel_dsi->lane_count, intel_dsi->burst_mode_ratio) + 1); } else { I915_WRITE(MIPI_HS_TX_TIMEOUT(port), - txbyteclkhs(adjusted_mode->vtotal * - adjusted_mode->htotal, + txbyteclkhs(adjusted_mode->crtc_vtotal * + adjusted_mode->crtc_htotal, bpp, intel_dsi->lane_count, intel_dsi->burst_mode_ratio) + 1); } diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 0bc8aa8b81c7..555afbcb6043 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -285,11 +285,11 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder) dvo_val |= DVO_VSYNC_ACTIVE_HIGH; /*I915_WRITE(DVOB_SRCDIM, - (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | - (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ + (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ I915_WRITE(dvo_srcdim_reg, - (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | - (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); + (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); /*I915_WRITE(DVOB, dvo_val);*/ I915_WRITE(dvo_reg, dvo_val); } diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 4294f605fe00..2806049e3a62 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -113,51 +113,51 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, x = y = width = height = 0; /* Native modes don't need fitting */ - if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && - adjusted_mode->vdisplay == pipe_config->pipe_src_h) + if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w && + adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h) goto done; switch (fitting_mode) { case DRM_MODE_SCALE_CENTER: width = pipe_config->pipe_src_w; height = pipe_config->pipe_src_h; - x = (adjusted_mode->hdisplay - width + 1)/2; - y = (adjusted_mode->vdisplay - height + 1)/2; + x = (adjusted_mode->crtc_hdisplay - width + 1)/2; + y = (adjusted_mode->crtc_vdisplay - height + 1)/2; break; case DRM_MODE_SCALE_ASPECT: /* Scale but preserve the aspect ratio */ { - u32 scaled_width = adjusted_mode->hdisplay + u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_config->pipe_src_h; u32 scaled_height = pipe_config->pipe_src_w - * adjusted_mode->vdisplay; + * adjusted_mode->crtc_vdisplay; if (scaled_width > scaled_height) { /* pillar */ width = scaled_height / pipe_config->pipe_src_h; if (width & 1) width++; - x = (adjusted_mode->hdisplay - width + 1) / 2; + x = (adjusted_mode->crtc_hdisplay - width + 1) / 2; y = 0; - height = adjusted_mode->vdisplay; + height = adjusted_mode->crtc_vdisplay; } else if (scaled_width < scaled_height) { /* letter */ height = scaled_width / pipe_config->pipe_src_w; if (height & 1) height++; - y = (adjusted_mode->vdisplay - height + 1) / 2; + y = (adjusted_mode->crtc_vdisplay - height + 1) / 2; x = 0; - width = adjusted_mode->hdisplay; + width = adjusted_mode->crtc_hdisplay; } else { x = y = 0; - width = adjusted_mode->hdisplay; - height = adjusted_mode->vdisplay; + width = adjusted_mode->crtc_hdisplay; + height = adjusted_mode->crtc_vdisplay; } } break; case DRM_MODE_SCALE_FULLSCREEN: x = y = 0; - width = adjusted_mode->hdisplay; - height = adjusted_mode->vdisplay; + width = adjusted_mode->crtc_hdisplay; + height = adjusted_mode->crtc_vdisplay; break; default: @@ -182,7 +182,7 @@ centre_horizontally(struct drm_display_mode *adjusted_mode, blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; sync_pos = (blank_width - sync_width + 1) / 2; - border = (adjusted_mode->hdisplay - width + 1) / 2; + border = (adjusted_mode->crtc_hdisplay - width + 1) / 2; border += border & 1; /* make the border even */ adjusted_mode->crtc_hdisplay = width; @@ -204,7 +204,7 @@ centre_vertically(struct drm_display_mode *adjusted_mode, blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start; sync_pos = (blank_width - sync_width + 1) / 2; - border = (adjusted_mode->vdisplay - height + 1) / 2; + border = (adjusted_mode->crtc_vdisplay - height + 1) / 2; adjusted_mode->crtc_vdisplay = height; adjusted_mode->crtc_vblank_start = height + border; @@ -231,10 +231,10 @@ static void i965_scale_aspect(struct intel_crtc_state *pipe_config, u32 *pfit_control) { struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - u32 scaled_width = adjusted_mode->hdisplay * + u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_config->pipe_src_h; u32 scaled_height = pipe_config->pipe_src_w * - adjusted_mode->vdisplay; + adjusted_mode->crtc_vdisplay; /* 965+ is easy, it does everything in hw */ if (scaled_width > scaled_height) @@ -243,7 +243,7 @@ static void i965_scale_aspect(struct intel_crtc_state *pipe_config, else if (scaled_width < scaled_height) *pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER; - else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) + else if (adjusted_mode->crtc_hdisplay != pipe_config->pipe_src_w) *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; } @@ -252,10 +252,10 @@ static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config, u32 *border) { struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - u32 scaled_width = adjusted_mode->hdisplay * + u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_config->pipe_src_h; u32 scaled_height = pipe_config->pipe_src_w * - adjusted_mode->vdisplay; + adjusted_mode->crtc_vdisplay; u32 bits; /* @@ -269,9 +269,9 @@ static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config, pipe_config->pipe_src_h); *border = LVDS_BORDER_ENABLE; - if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) { + if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay) { bits = panel_fitter_scaling(pipe_config->pipe_src_h, - adjusted_mode->vdisplay); + adjusted_mode->crtc_vdisplay); *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | bits << PFIT_VERT_SCALE_SHIFT); @@ -285,9 +285,9 @@ static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config, pipe_config->pipe_src_w); *border = LVDS_BORDER_ENABLE; - if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) { + if (pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) { bits = panel_fitter_scaling(pipe_config->pipe_src_w, - adjusted_mode->hdisplay); + adjusted_mode->crtc_hdisplay); *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | bits << PFIT_VERT_SCALE_SHIFT); @@ -315,8 +315,8 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, adjusted_mode = &pipe_config->base.adjusted_mode; /* Native modes don't need fitting */ - if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && - adjusted_mode->vdisplay == pipe_config->pipe_src_h) + if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w && + adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h) goto out; switch (fitting_mode) { @@ -342,8 +342,8 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, * Full scaling, even if it changes the aspect ratio. * Fortunately this is all done for us in hw. */ - if (pipe_config->pipe_src_h != adjusted_mode->vdisplay || - pipe_config->pipe_src_w != adjusted_mode->hdisplay) { + if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay || + pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) { pfit_control |= PFIT_ENABLE; if (INTEL_INFO(dev)->gen >= 4) pfit_control |= PFIT_SCALING_AUTO; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ab75b6146e84..9df6bbd1872c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -605,9 +605,9 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, static int intel_sdvo_get_pixel_multiplier(const struct drm_display_mode *adjusted_mode) { - if (adjusted_mode->clock >= 100000) + if (adjusted_mode->crtc_clock >= 100000) return 1; - else if (adjusted_mode->clock >= 50000) + else if (adjusted_mode->crtc_clock >= 50000) return 2; else return 4; From 28b468a008888928ce59bc2528713b913be60baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 13:40:48 +0300 Subject: [PATCH 023/134] drm/i915: Move HDMI aspect ratio setup to .compute_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We shouldn't frob adjusted_mode after .compute_config(), so move the infoframe aspect ratio setup to .compute_config() from intel_hdmi_set_avi_infoframe(). Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kahola Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index c11703a0e6b1..08f8399f8418 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -454,9 +454,6 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, union hdmi_infoframe frame; int ret; - /* Set user selected PAR to incoming mode's member */ - adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio; - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, adjusted_mode); if (ret < 0) { @@ -1312,6 +1309,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, return false; } + /* Set user selected PAR to incoming mode's member */ + adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio; + return true; } From 7c5f93b05efc72feb206348da00a0a77e631a3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 13:40:49 +0300 Subject: [PATCH 024/134] drm/i915: Constify adjusted_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make adjusted_mode const whereever we don't have to modify it. This only covers cases when we have a local adjusted_mode variable, and doesn't make any difference for cases where we just dereference pipe_config->adjusted_mode. Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kahola Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo.h | 4 ++-- drivers/gpu/drm/i915/dvo_ch7017.c | 4 ++-- drivers/gpu/drm/i915/dvo_ch7xxx.c | 4 ++-- drivers/gpu/drm/i915/dvo_ivch.c | 4 ++-- drivers/gpu/drm/i915/dvo_ns2501.c | 4 ++-- drivers/gpu/drm/i915/dvo_sil164.c | 4 ++-- drivers/gpu/drm/i915/dvo_tfp410.c | 4 ++-- drivers/gpu/drm/i915/intel_audio.c | 2 +- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_dp_mst.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 22 +++++++++++----------- drivers/gpu/drm/i915/intel_panel.c | 14 ++++---------- drivers/gpu/drm/i915/intel_pm.c | 9 +++------ drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 19 files changed, 44 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 312163379db9..0e2c1b9648a7 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -94,8 +94,8 @@ struct intel_dvo_dev_ops { * after this function is called. */ void (*mode_set)(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); /* * Probe for a connected output, and return detect_status. diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c index 86b27d1d90c2..cbb22027a3ce 100644 --- a/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/dvo_ch7017.c @@ -255,8 +255,8 @@ static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, } static void ch7017_mode_set(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; uint8_t outputs_enable, lvds_control_2, lvds_power_down; diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index 80449f475960..4b4acc1a06fe 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -275,8 +275,8 @@ static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, } static void ch7xxx_mode_set(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { uint8_t tvco, tpcp, tpd, tlpf, idf; diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index e082f75317a0..ff9f1b077d83 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -394,8 +394,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo) } static void ivch_mode_set(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct ivch_priv *priv = dvo->dev_priv; uint16_t vr40 = 0; diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index 97ae8aa157e9..063859fff0f0 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -546,8 +546,8 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, } static void ns2501_mode_set(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { const struct ns2501_configuration *conf; struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c index fa0114967076..26f13eb634f9 100644 --- a/drivers/gpu/drm/i915/dvo_sil164.c +++ b/drivers/gpu/drm/i915/dvo_sil164.c @@ -190,8 +190,8 @@ static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, } static void sil164_mode_set(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { /* As long as the basics are set up, since we don't have clock * dependencies in the mode setup, we can just leave the diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c index 7853719a0e81..6f1a0a6d4e22 100644 --- a/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/dvo_tfp410.c @@ -222,8 +222,8 @@ static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo, } static void tfp410_mode_set(struct intel_dvo_device *dvo, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { /* As long as the basics are set up, since we don't have clock dependencies * in the mode setup, we can just leave the registers alone and everything diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index e4c30e8c2674..b08b4a7fae49 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -397,7 +397,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); - struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; struct drm_connector *connector; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6ce38e3edf21..cac7928ebc49 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -158,7 +158,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crt *crt = intel_encoder_to_crt(encoder); struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; u32 adpa; if (INTEL_INFO(dev)->gen >= 5) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5105e09b65cc..47bf13ff5e24 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4392,7 +4392,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, int skl_update_scaler_crtc(struct intel_crtc_state *state) { struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); - struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode; DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); @@ -6477,7 +6477,7 @@ static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, struct intel_crtc_state *pipe_config) { struct drm_device *dev = intel_crtc->base.dev; - struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; int lane, link_bw, fdi_dotclock, ret; bool needs_recompute = false; @@ -6556,7 +6556,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { @@ -7624,7 +7624,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; uint32_t crtc_vtotal, crtc_vblank_end; int vsyncshift = 0; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 06a2b1046daf..77f733007e32 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1587,7 +1587,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder) struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); enum port port = dp_to_dig_port(intel_dp)->port; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; intel_dp_set_link_params(intel_dp, crtc->config); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index cccf014d55c1..ca4d0220ecd4 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -40,7 +40,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_atomic_state *state; int bpp, i; int lane_count, slots; - struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; struct drm_connector *drm_connector; struct intel_connector *connector, *found = NULL; struct drm_connector_state *connector_state; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c96289dba380..c98ed81c3a2e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -683,7 +683,7 @@ struct intel_hdmi { const void *frame, ssize_t len); void (*set_infoframes)(struct drm_encoder *encoder, bool enable, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *adjusted_mode); bool (*infoframe_enabled)(struct drm_encoder *encoder); }; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 4fb97c07bbc2..eb86ba7faaac 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -774,7 +774,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); - struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; enum port port; unsigned int bpp = intel_crtc->config->pipe_bpp; u32 val, tmp; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 555afbcb6043..8492053e0ff0 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -251,7 +251,7 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; struct intel_dvo *intel_dvo = enc_to_dvo(encoder); int pipe = crtc->pipe; u32 dvo_val; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 08f8399f8418..af231ede4776 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -447,7 +447,7 @@ static void intel_write_infoframe(struct drm_encoder *encoder, } static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -491,7 +491,7 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) static void intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { union hdmi_infoframe frame; int ret; @@ -506,7 +506,7 @@ intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, static void g4x_set_infoframes(struct drm_encoder *encoder, bool enable, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); @@ -658,7 +658,7 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) static void ibx_set_infoframes(struct drm_encoder *encoder, bool enable, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -710,7 +710,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, static void cpt_set_infoframes(struct drm_encoder *encoder, bool enable, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -752,7 +752,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, static void vlv_set_infoframes(struct drm_encoder *encoder, bool enable, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); @@ -804,7 +804,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, static void hsw_set_infoframes(struct drm_encoder *encoder, bool enable, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -841,7 +841,7 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); - struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; u32 hdmi_val; hdmi_val = SDVO_ENCODING_HDMI; @@ -1537,7 +1537,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; intel_hdmi_prepare(encoder); @@ -1554,7 +1554,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; enum dpio_channel port = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; u32 val; @@ -1820,7 +1820,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; enum dpio_channel ch = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; int data, i, stagger; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 2806049e3a62..dd71e7f139e3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -105,12 +105,8 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, struct intel_crtc_state *pipe_config, int fitting_mode) { - struct drm_display_mode *adjusted_mode; - int x, y, width, height; - - adjusted_mode = &pipe_config->base.adjusted_mode; - - x = y = width = height = 0; + const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; + int x = 0, y = 0, width = 0, height = 0; /* Native modes don't need fitting */ if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w && @@ -230,7 +226,7 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target) static void i965_scale_aspect(struct intel_crtc_state *pipe_config, u32 *pfit_control) { - struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_config->pipe_src_h; u32 scaled_height = pipe_config->pipe_src_w * @@ -310,9 +306,7 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, { struct drm_device *dev = intel_crtc->base.dev; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; - struct drm_display_mode *adjusted_mode; - - adjusted_mode = &pipe_config->base.adjusted_mode; + struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; /* Native modes don't need fitting */ if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w && diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d5c60bbb9c4c..7da3358405d4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -703,12 +703,9 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc) crtc = single_enabled_crtc(dev); if (crtc) { - const struct drm_display_mode *adjusted_mode; + const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode; int pixel_size = crtc->primary->state->fb->bits_per_pixel / 8; - int clock; - - adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode; - clock = adjusted_mode->crtc_clock; + int clock = adjusted_mode->crtc_clock; /* Display SR */ wm = intel_calculate_wm(clock, &pineview_display_wm, @@ -2086,7 +2083,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode; u32 linetime, ips_linetime; if (!intel_crtc->active) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9df6bbd1872c..857b1bd71156 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1189,7 +1189,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder) struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc); - struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; struct drm_display_mode *mode = &crtc->config->base.mode; struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); u32 sdvox; From 7949dd47ba58e0fb7effd4651afa4468ba240460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 25 Sep 2015 16:39:30 +0300 Subject: [PATCH 025/134] drm/i915: Add HDMI aspect ratio property for SDVO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the HDMI aspect ratio property the same way in the SDVO code as we handle it in the HDMI code. v2: Remove stray whitespace change Signed-off-by: Ville Syrjälä Reviewed-by: Mika Kahola Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_hdmi.c | 9 --------- drivers/gpu/drm/i915/intel_modes.c | 9 +++++++++ drivers/gpu/drm/i915/intel_sdvo.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c98ed81c3a2e..ed66a4f26dbd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1300,6 +1300,7 @@ int intel_connector_update_modes(struct drm_connector *connector, int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); void intel_attach_force_audio_property(struct drm_connector *connector); void intel_attach_broadcast_rgb_property(struct drm_connector *connector); +void intel_attach_aspect_ratio_property(struct drm_connector *connector); /* intel_overlay.c */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index af231ede4776..3c5f2c922180 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2003,15 +2003,6 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { .destroy = intel_encoder_destroy, }; -static void -intel_attach_aspect_ratio_property(struct drm_connector *connector) -{ - if (!drm_mode_create_aspect_ratio_property(connector->dev)) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.aspect_ratio_property, - DRM_MODE_PICTURE_ASPECT_NONE); -} - static void intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) { diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 0e860f39933d..38a4c8ce7e63 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -126,3 +126,12 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector) drm_object_attach_property(&connector->base, prop, 0); } + +void +intel_attach_aspect_ratio_property(struct drm_connector *connector) +{ + if (!drm_mode_create_aspect_ratio_property(connector->dev)) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.aspect_ratio_property, + DRM_MODE_PICTURE_ASPECT_NONE); +} diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 857b1bd71156..c42b636c2087 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -106,6 +106,11 @@ struct intel_sdvo { uint32_t color_range; bool color_range_auto; + /** + * HDMI user specified aspect ratio + */ + enum hdmi_picture_aspect aspect_ratio; + /** * This is set if we're going to treat the device as TV-out. * @@ -1181,6 +1186,10 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, if (intel_sdvo->is_tv) i9xx_adjust_sdvo_tv_clock(pipe_config); + /* Set user selected PAR to incoming mode's member */ + if (intel_sdvo->is_hdmi) + adjusted_mode->picture_aspect_ratio = intel_sdvo->aspect_ratio; + return true; } @@ -2043,6 +2052,23 @@ intel_sdvo_set_property(struct drm_connector *connector, goto done; } + if (property == connector->dev->mode_config.aspect_ratio_property) { + switch (val) { + case DRM_MODE_PICTURE_ASPECT_NONE: + intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; + break; + case DRM_MODE_PICTURE_ASPECT_4_3: + intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_4_3; + break; + case DRM_MODE_PICTURE_ASPECT_16_9: + intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_16_9; + break; + default: + return -EINVAL; + } + goto done; + } + #define CHECK_PROPERTY(name, NAME) \ if (intel_sdvo_connector->name == property) { \ if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ @@ -2382,6 +2408,8 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, intel_attach_broadcast_rgb_property(&connector->base.base); intel_sdvo->color_range_auto = true; } + intel_attach_aspect_ratio_property(&connector->base.base); + intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; } static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) From ab9cc558a3d793b8643846940f16faa440f7d32b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:24 +0300 Subject: [PATCH 026/134] drm/i915: Parametrize UOS_RSA_SCRATCH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_guc_reg.h | 2 +- drivers/gpu/drm/i915/intel_guc_loader.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h index b35566164c4d..c4cb1c0c4d0d 100644 --- a/drivers/gpu/drm/i915/i915_guc_reg.h +++ b/drivers/gpu/drm/i915/i915_guc_reg.h @@ -41,7 +41,7 @@ #define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) -#define UOS_RSA_SCRATCH_0 0xc200 +#define UOS_RSA_SCRATCH(i) (0xc200 + (i) * 4) #define DMA_ADDR_0_LOW 0xc300 #define DMA_ADDR_0_HIGH 0xc304 #define DMA_ADDR_1_LOW 0xc308 diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 40241f37e24b..5d17b63c107c 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -258,7 +258,7 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv) /* Copy RSA signature from the fw image to HW for verification */ sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset); for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++) - I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(u32), rsa[i]); + I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); /* Set the source address for the new blob */ offset = i915_gem_obj_ggtt_offset(fw_obj); From 7e435ad2c263cf3fd51343b0754856f2d88b0cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:25 +0300 Subject: [PATCH 027/134] drm/i915: Add LO/HI PRIVATE_PAT registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 ++++---- drivers/gpu/drm/i915/i915_reg.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 47344d068f9a..620d57e2526b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2889,8 +2889,8 @@ static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv) /* XXX: spec defines this as 2 distinct registers. It's unclear if a 64b * write would work. */ - I915_WRITE(GEN8_PRIVATE_PAT, pat); - I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32); + I915_WRITE(GEN8_PRIVATE_PAT_LO, pat); + I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32); } static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) @@ -2924,8 +2924,8 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) GEN8_PPAT(6, CHV_PPAT_SNOOP) | GEN8_PPAT(7, CHV_PPAT_SNOOP); - I915_WRITE(GEN8_PRIVATE_PAT, pat); - I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32); + I915_WRITE(GEN8_PRIVATE_PAT_LO, pat); + I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32); } static int gen8_gmch_probe(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d5a07906721f..39b92135f549 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1551,7 +1551,8 @@ enum skl_disp_power_wells { #define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3) #define RING_FAULT_VALID (1<<0) #define DONE_REG 0x40b0 -#define GEN8_PRIVATE_PAT 0x40e0 +#define GEN8_PRIVATE_PAT_LO 0x40e0 +#define GEN8_PRIVATE_PAT_HI (0x40e0 + 4) #define BSD_HWS_PGA_GEN7 (0x04180) #define BLT_HWS_PGA_GEN7 (0x04280) #define VEBOX_HWS_PGA_GEN7 (0x04380) From d3a93cbe47bfb49de2d517d68c7082cef176dbb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:26 +0300 Subject: [PATCH 028/134] drm/i915: Always use GEN8_RING_PDP_{LDW, UDW} instead of hand rolling the register offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 879771766973..007d8920eb2f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2231,10 +2231,9 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev) for_each_ring(ring, dev_priv, unused) { seq_printf(m, "%s\n", ring->name); for (i = 0; i < 4; i++) { - u32 offset = 0x270 + i * 8; - u64 pdp = I915_READ(ring->mmio_base + offset + 4); + u64 pdp = I915_READ(GEN8_RING_PDP_UDW(ring, i)); pdp <<= 32; - pdp |= I915_READ(ring->mmio_base + offset); + pdp |= I915_READ(GEN8_RING_PDP_LDW(ring, i)); seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp); } } From c039b7f2bf2e872b7b85d089ecf2f3cef215952e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:27 +0300 Subject: [PATCH 029/134] drm/i915: Include MCHBAR_MIRROR_BASE in ILK_GDSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_uncore.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 39b92135f549..08d78fc55f2b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -105,7 +105,7 @@ #define GRDOM_RESET_STATUS (1<<1) #define GRDOM_RESET_ENABLE (1<<0) -#define ILK_GDSR 0x2ca4 /* MCHBAR offset */ +#define ILK_GDSR (MCHBAR_MIRROR_BASE + 0x2ca4) #define ILK_GRDOM_FULL (0<<1) #define ILK_GRDOM_RENDER (1<<1) #define ILK_GRDOM_MEDIA (3<<1) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 14d0831c6156..b43c6d025ac3 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1429,21 +1429,21 @@ static int ironlake_do_reset(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, + I915_WRITE(ILK_GDSR, ILK_GRDOM_RENDER | ILK_GRDOM_RESET_ENABLE); - ret = wait_for((I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & + ret = wait_for((I915_READ(ILK_GDSR) & ILK_GRDOM_RESET_ENABLE) == 0, 500); if (ret) return ret; - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, + I915_WRITE(ILK_GDSR, ILK_GRDOM_MEDIA | ILK_GRDOM_RESET_ENABLE); - ret = wait_for((I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & + ret = wait_for((I915_READ(ILK_GDSR) & ILK_GRDOM_RESET_ENABLE) == 0, 500); if (ret) return ret; - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, 0); + I915_WRITE(ILK_GDSR, 0); return 0; } From f65a9c5bd7287b4e545b07a3551a1b05c1468349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:28 +0300 Subject: [PATCH 030/134] drm/i915: Parametrize PALETTE and LGC_PALETTE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 08d78fc55f2b..2c3f8b3dd29a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2485,8 +2485,8 @@ enum skl_disp_power_wells { #define PALETTE_A_OFFSET 0xa000 #define PALETTE_B_OFFSET 0xa800 #define CHV_PALETTE_C_OFFSET 0xc000 -#define PALETTE(pipe) (dev_priv->info.palette_offsets[pipe] + \ - dev_priv->info.display_mmio_offset) +#define PALETTE(pipe, i) (dev_priv->info.palette_offsets[pipe] + \ + dev_priv->info.display_mmio_offset + (i) * 4) /* MCH MMIO space */ @@ -5641,7 +5641,7 @@ enum skl_disp_power_wells { /* legacy palette */ #define _LGC_PALETTE_A 0x4a000 #define _LGC_PALETTE_B 0x4a800 -#define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) +#define LGC_PALETTE(pipe, i) (_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4) #define _GAMMA_MODE_A 0x4a480 #define _GAMMA_MODE_B 0x4ac80 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 47bf13ff5e24..203406b75bfe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4593,7 +4593,6 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; - int palreg = PALETTE(pipe); int i; bool reenable_ips = false; @@ -4608,10 +4607,6 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) assert_pll_enabled(dev_priv, pipe); } - /* use legacy palette for Ironlake */ - if (!HAS_GMCH_DISPLAY(dev)) - palreg = LGC_PALETTE(pipe); - /* Workaround : Do not read or write the pipe palette/gamma data while * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. */ @@ -4623,7 +4618,14 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) } for (i = 0; i < 256; i++) { - I915_WRITE(palreg + 4 * i, + u32 palreg; + + if (HAS_GMCH_DISPLAY(dev)) + palreg = PALETTE(pipe, i); + else + palreg = LGC_PALETTE(pipe, i); + + I915_WRITE(palreg, (intel_crtc->lut_r[i] << 16) | (intel_crtc->lut_g[i] << 8) | intel_crtc->lut_b[i]); From 0b87c24ea5ec9e950aaa0c933fa739a95aa43555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 22 Sep 2015 19:47:51 +0300 Subject: [PATCH 031/134] drm/i915: s/_CURACNTR/CURCNTR(PIPE_A)/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Deal with _CURABASE too Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 007d8920eb2f..7d88ecfe3e2b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2909,7 +2909,7 @@ static bool cursor_active(struct drm_device *dev, int pipe) u32 state; if (IS_845G(dev) || IS_I865G(dev)) - state = I915_READ(_CURACNTR) & CURSOR_ENABLE; + state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE; else state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 203406b75bfe..86f5a6ef11d8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1295,7 +1295,7 @@ static void assert_cursor(struct drm_i915_private *dev_priv, bool cur_state; if (IS_845G(dev) || IS_I865G(dev)) - cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE; + cur_state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE; else cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; @@ -9890,13 +9890,13 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base) /* On these chipsets we can only modify the base/size/stride * whilst the cursor is disabled. */ - I915_WRITE(_CURACNTR, 0); - POSTING_READ(_CURACNTR); + I915_WRITE(CURCNTR(PIPE_A), 0); + POSTING_READ(CURCNTR(PIPE_A)); intel_crtc->cursor_cntl = 0; } if (intel_crtc->cursor_base != base) { - I915_WRITE(_CURABASE, base); + I915_WRITE(CURBASE(PIPE_A), base); intel_crtc->cursor_base = base; } @@ -9906,8 +9906,8 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base) } if (intel_crtc->cursor_cntl != cntl) { - I915_WRITE(_CURACNTR, cntl); - POSTING_READ(_CURACNTR); + I915_WRITE(CURCNTR(PIPE_A), cntl); + POSTING_READ(CURCNTR(PIPE_A)); intel_crtc->cursor_cntl = cntl; } } From e66eb81de2ff8228cc888946f2c1e307d5b19373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:34 +0300 Subject: [PATCH 032/134] drm/i915: Add VLV_HDMIB etc. which already include VLV_DISPLAY_BASE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 +++++++- drivers/gpu/drm/i915/intel_display.c | 27 ++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2c3f8b3dd29a..59124a5714a9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3274,7 +3274,9 @@ enum skl_disp_power_wells { #define GEN3_SDVOC 0x61160 #define GEN4_HDMIB GEN3_SDVOB #define GEN4_HDMIC GEN3_SDVOC -#define CHV_HDMID 0x6116C +#define VLV_HDMIB (VLV_DISPLAY_BASE + GEN4_HDMIB) +#define VLV_HDMIC (VLV_DISPLAY_BASE + GEN4_HDMIC) +#define CHV_HDMID (VLV_DISPLAY_BASE + 0x6116C) #define PCH_SDVOB 0xe1140 #define PCH_HDMIB PCH_SDVOB #define PCH_HDMIC 0xe1150 @@ -4103,6 +4105,10 @@ enum skl_disp_power_wells { #define DP_C 0x64200 #define DP_D 0x64300 +#define VLV_DP_B (VLV_DISPLAY_BASE + DP_B) +#define VLV_DP_C (VLV_DISPLAY_BASE + DP_C) +#define CHV_DP_D (VLV_DISPLAY_BASE + DP_D) + #define DP_PORT_EN (1 << 31) #define DP_PIPEB_SELECT (1 << 30) #define DP_PIPE_MASK (1 << 30) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 86f5a6ef11d8..91dba4f65d2b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14050,29 +14050,26 @@ static void intel_setup_outputs(struct drm_device *dev) * eDP ports. Consult the VBT as well as DP_DETECTED to * detect eDP ports. */ - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED && + if (I915_READ(VLV_HDMIB) & SDVO_DETECTED && !intel_dp_is_edp(dev, PORT_B)) - intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, - PORT_B); - if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED || + intel_hdmi_init(dev, VLV_HDMIB, PORT_B); + if (I915_READ(VLV_DP_B) & DP_DETECTED || intel_dp_is_edp(dev, PORT_B)) - intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); + intel_dp_init(dev, VLV_DP_B, PORT_B); - if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED && + if (I915_READ(VLV_HDMIC) & SDVO_DETECTED && !intel_dp_is_edp(dev, PORT_C)) - intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, - PORT_C); - if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED || + intel_hdmi_init(dev, VLV_HDMIC, PORT_C); + if (I915_READ(VLV_DP_C) & DP_DETECTED || intel_dp_is_edp(dev, PORT_C)) - intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); + intel_dp_init(dev, VLV_DP_C, PORT_C); if (IS_CHERRYVIEW(dev)) { - if (I915_READ(VLV_DISPLAY_BASE + CHV_HDMID) & SDVO_DETECTED) - intel_hdmi_init(dev, VLV_DISPLAY_BASE + CHV_HDMID, - PORT_D); /* eDP not supported on port D, so don't check VBT */ - if (I915_READ(VLV_DISPLAY_BASE + DP_D) & DP_DETECTED) - intel_dp_init(dev, VLV_DISPLAY_BASE + DP_D, PORT_D); + if (I915_READ(CHV_HDMID) & SDVO_DETECTED) + intel_hdmi_init(dev, CHV_HDMID, PORT_D); + if (I915_READ(CHV_DP_D) & DP_DETECTED) + intel_dp_init(dev, CHV_DP_D, PORT_D); } intel_dsi_init(dev); From 77179400cdf61f189fecb379e23347027b9ea68d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:35 +0300 Subject: [PATCH 033/134] drm/i915: s/DDI_BUF_CTL_A/DDI_BUF_CTL(PORT_A)/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 91dba4f65d2b..7f3c482be1f4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13989,7 +13989,7 @@ static void intel_setup_outputs(struct drm_device *dev) * On SKL pre-D0 the strap isn't connected, so we assume * it's there. */ - found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED; + found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED; /* WaIgnoreDDIAStrap: skl */ if (found || IS_SKYLAKE(dev)) intel_ddi_init(dev, PORT_A); From 1170f28c0f7a450e1cb7f31ed2968e8be751b4fc Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Fri, 25 Sep 2015 14:00:32 +0300 Subject: [PATCH 034/134] drm/i915: Add CD and pixel clock information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds information of current and maximum CD clock frequency and pixel clock frequency information on 'i915_debugfs.c'. v2: - combined seperate patches for current CD clock, maximum CD clock and maximum pixel clock - space added between the frequency value and the unit Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7d88ecfe3e2b..afa79827f1f7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1309,6 +1309,10 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_puts(m, "no P-state info available\n"); } + seq_printf(m, "Current CD clock frequency: %d kHz\n", dev_priv->cdclk_freq); + seq_printf(m, "Max CD clock frequency: %d kHz\n", dev_priv->max_cdclk_freq); + seq_printf(m, "Max pixel clock frequency: %d kHz\n", dev_priv->max_dotclk_freq); + out: intel_runtime_pm_put(dev_priv); return ret; From aa0011a896bc1d9aa35a1ed12da63dca92e7b3f1 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 14:33:35 +0100 Subject: [PATCH 035/134] drm/i915/gen9: Handle error returned by gen9_init_workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 16a4eada60a1..2042bc51cdbb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1041,10 +1041,13 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *ring) static int skl_init_workarounds(struct intel_engine_cs *ring) { + int ret; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - gen9_init_workarounds(ring); + ret = gen9_init_workarounds(ring); + if (ret) + return ret; /* WaDisablePowerCompilerClockGating:skl */ if (INTEL_REVID(dev) == SKL_REVID_B0) @@ -1081,10 +1084,13 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) static int bxt_init_workarounds(struct intel_engine_cs *ring) { + int ret; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - gen9_init_workarounds(ring); + ret = gen9_init_workarounds(ring); + if (ret) + return ret; /* WaDisableThreadStallDopClockGating:bxt */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, From 60294683d4becb011f5e181062fd5214cf3690bd Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 14:33:37 +0100 Subject: [PATCH 036/134] drm/i915/gen9: Merge two WA as they part of same register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge Wa4x4STCOptimizationDisable and WaDisablePartialResolveInVc to save an entry in WA array. Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2042bc51cdbb..a0b2219baf77 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -961,10 +961,9 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) } /* Wa4x4STCOptimizationDisable:skl,bxt */ - WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); - /* WaDisablePartialResolveInVc:skl,bxt */ - WA_SET_BIT_MASKED(CACHE_MODE_1, GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE); + WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE | + GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE)); /* WaCcsTlbPrefetchDisable:skl,bxt */ WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, From aa66c506f1c40af4fbb383ac35069b7baca7642c Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 14:33:40 +0100 Subject: [PATCH 037/134] drm/i915/bxt: Add WaStoreMultiplePTEenable name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated WA with the name. Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7da3358405d4..c96055933064 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -127,13 +127,10 @@ static void bxt_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ); - if (INTEL_REVID(dev) == BXT_REVID_A0) { - /* - * Hardware specification requires this bit to be - * set to 1 for A0 - */ + /* WaStoreMultiplePTEenable:bxt */ + /* This is a requirement according to Hardware specification */ + if (INTEL_REVID(dev) == BXT_REVID_A0) I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF); - } /* WaSetClckGatingDisableMedia:bxt */ if (INTEL_REVID(dev) == BXT_REVID_A0) { From 68fc2b76a16c4dd6c768c838f91d956475e1b3df Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 14:33:42 +0100 Subject: [PATCH 038/134] drm/i915/skl: Remove WaDisableSDEUnitClockGating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping it because it is for pre-production stepping. Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c96055933064..eb5498a6a1e6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -73,12 +73,10 @@ static void skl_init_clock_gating(struct drm_device *dev) if (INTEL_REVID(dev) <= SKL_REVID_B0) { /* - * WaDisableSDEUnitClockGating:skl * WaSetGAPSunitClckGateDisable:skl */ I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | - GEN8_GAPSUNIT_CLOCK_GATE_DISABLE | - GEN8_SDEUNIT_CLOCK_GATE_DISABLE); + GEN8_GAPSUNIT_CLOCK_GATE_DISABLE); /* WaDisableVFUnitClockGating:skl */ I915_WRITE(GEN6_UCGCTL2, I915_READ(GEN6_UCGCTL2) | From 7019f0a7a68258ba05e6e5b17ef49ec547610a33 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 14:33:43 +0100 Subject: [PATCH 039/134] drm/i915/skl: Remove WaSetGAPSunitClckGateDisable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping it because it is for pre-production stepping, also removed bit definition in i915_reg as it is not used anywhere else. Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä [danvet: Keep define as Ville suggested.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index eb5498a6a1e6..ebb83564f60f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -72,12 +72,6 @@ static void skl_init_clock_gating(struct drm_device *dev) gen9_init_clock_gating(dev); if (INTEL_REVID(dev) <= SKL_REVID_B0) { - /* - * WaSetGAPSunitClckGateDisable:skl - */ - I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | - GEN8_GAPSUNIT_CLOCK_GATE_DISABLE); - /* WaDisableVFUnitClockGating:skl */ I915_WRITE(GEN6_UCGCTL2, I915_READ(GEN6_UCGCTL2) | GEN6_VFUNIT_CLOCK_GATE_DISABLE); From 010e9f5fad88bce83dc21a864540fcbf6d17e9b3 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 14:33:44 +0100 Subject: [PATCH 040/134] drm/i915/skl: Remove WaDisableVFUnitClockGating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping it because it is for pre-production stepping, also removed bit definition in i915_reg.h as it is not used anywhere else. Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä [danvet: Keep #define as Ville suggested.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ebb83564f60f..780b1e01d333 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -71,12 +71,6 @@ static void skl_init_clock_gating(struct drm_device *dev) gen9_init_clock_gating(dev); - if (INTEL_REVID(dev) <= SKL_REVID_B0) { - /* WaDisableVFUnitClockGating:skl */ - I915_WRITE(GEN6_UCGCTL2, I915_READ(GEN6_UCGCTL2) | - GEN6_VFUNIT_CLOCK_GATE_DISABLE); - } - if (INTEL_REVID(dev) <= SKL_REVID_D0) { /* WaDisableHDCInvalidation:skl */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | From e9a64adaec93ce5dfcdee44bbd89c90b4d997f6f Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:37 +0100 Subject: [PATCH 041/134] drm/i915/gen8: Add gen8_init_workarounds for common WA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WA in this function should be ordered based on register address. The following order is suggested (Ville), instpm mi_mode row chicken half slice chicken common slice chicken hdc chicken cache_mode_0 cache_mode_1 gt_mode Cc: Ville Syrjälä Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a0b2219baf77..2c4f097acd0e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -800,11 +800,22 @@ static int wa_add(struct drm_i915_private *dev_priv, #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val) +static int gen8_init_workarounds(struct intel_engine_cs *ring) +{ + + return 0; +} + static int bdw_init_workarounds(struct intel_engine_cs *ring) { + int ret; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + ret = gen8_init_workarounds(ring); + if (ret) + return ret; + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); /* WaDisableAsyncFlipPerfMode:bdw */ @@ -868,9 +879,14 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) static int chv_init_workarounds(struct intel_engine_cs *ring) { + int ret; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + ret = gen8_init_workarounds(ring); + if (ret) + return ret; + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); /* WaDisableAsyncFlipPerfMode:chv */ From 68c6198b33d22af5ac1649554f6b8982ea587a72 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:38 +0100 Subject: [PATCH 042/134] drm/i915/gen8: Move INSTPM WA to common function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2c4f097acd0e..76e548889d6a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -802,6 +802,10 @@ static int wa_add(struct drm_i915_private *dev_priv, static int gen8_init_workarounds(struct intel_engine_cs *ring) { + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); return 0; } @@ -816,8 +820,6 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); - /* WaDisableAsyncFlipPerfMode:bdw */ WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); @@ -887,8 +889,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); - /* WaDisableAsyncFlipPerfMode:chv */ WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); From 717d84d67e3a95f440c37c7482681b3535fdc7e2 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:39 +0100 Subject: [PATCH 043/134] drm/i915/gen8: Move WaDisableAsyncFlipPerfMode to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 76e548889d6a..ccb8c18d1af0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -807,6 +807,9 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisableAsyncFlipPerfMode:bdw,chv */ + WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + return 0; } @@ -820,9 +823,6 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - /* WaDisableAsyncFlipPerfMode:bdw */ - WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); - /* WaDisablePartialInstShootdown:bdw */ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -889,9 +889,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - /* WaDisableAsyncFlipPerfMode:chv */ - WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); - /* WaDisablePartialInstShootdown:chv */ /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, From d0581194566eb9744fa657812b2693556392451b Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:40 +0100 Subject: [PATCH 044/134] drm/i915/gen8: Move WaDisablePartialInstShootdown to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ccb8c18d1af0..8c1d17ac7d4c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -810,6 +810,10 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) /* WaDisableAsyncFlipPerfMode:bdw,chv */ WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + /* WaDisablePartialInstShootdown:bdw,chv */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, + PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + return 0; } @@ -823,11 +827,8 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - /* WaDisablePartialInstShootdown:bdw */ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, - PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE | - STALL_DOP_GATING_DISABLE); + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); /* WaDisableDopClockGating:bdw */ WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, @@ -889,11 +890,8 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - /* WaDisablePartialInstShootdown:chv */ /* WaDisableThreadStallDopClockGating:chv */ - WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, - PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE | - STALL_DOP_GATING_DISABLE); + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); /* Use Force Non-Coherent whenever executing a 3D context. This is a * workaround for a possible hang in the unlikely event a TLB From 6def8fdd5d9528db7fb6dfebd994491f6ba45785 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:42 +0100 Subject: [PATCH 045/134] drm/i915/gen8: Move HiZ RAW stall optimization disable WA to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8c1d17ac7d4c..6adc7f110568 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -814,6 +814,16 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: + * "The Hierarchical Z RAW Stall Optimization allows non-overlapping + * polygons in the same 8x4 pixel/sample area to be processed without + * stalling waiting for the earlier ones to write to Hierarchical Z + * buffer." + * + * This optimization is off by default for BDW and CHV; turn it on. + */ + WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); + return 0; } @@ -851,16 +861,6 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */ (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); - /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: - * "The Hierarchical Z RAW Stall Optimization allows non-overlapping - * polygons in the same 8x4 pixel/sample area to be processed without - * stalling waiting for the earlier ones to write to Hierarchical Z - * buffer." - * - * This optimization is off by default for Broadwell; turn it on. - */ - WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); - /* Wa4x4STCOptimizationDisable:bdw */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); @@ -903,11 +903,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) HDC_FORCE_NON_COHERENT | HDC_DONOT_FETCH_MEM_WHEN_MASKED); - /* According to the CACHE_MODE_0 default value documentation, some - * CHV platforms disable this optimization by default. Turn it on. - */ - WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); - /* Wa4x4STCOptimizationDisable:chv */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); From 484046362fcee7ad0c67e1c10c4c346fb14cf420 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:43 +0100 Subject: [PATCH 046/134] drm/i915/gen8: Move Wa4x4STCOptimizationDisable to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6adc7f110568..d72e072cce83 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -824,6 +824,9 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) */ WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE); + /* Wa4x4STCOptimizationDisable:bdw,chv */ + WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); + return 0; } @@ -861,10 +864,6 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */ (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); - /* Wa4x4STCOptimizationDisable:bdw */ - WA_SET_BIT_MASKED(CACHE_MODE_1, - GEN8_4x4_STC_OPTIMIZATION_DISABLE); - /* * BSpec recommends 8x4 when MSAA is used, * however in practice 16x4 seems fastest. @@ -903,10 +902,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) HDC_FORCE_NON_COHERENT | HDC_DONOT_FETCH_MEM_WHEN_MASKED); - /* Wa4x4STCOptimizationDisable:chv */ - WA_SET_BIT_MASKED(CACHE_MODE_1, - GEN8_4x4_STC_OPTIMIZATION_DISABLE); - /* Improve HiZ throughput on CHV. */ WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); From 7eebcde6e526a53e06d238f6daf788df3c8e7620 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:44 +0100 Subject: [PATCH 047/134] drm/i915/gen8: Move GEN7_GT_MODE WA to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 36 +++++++++---------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d72e072cce83..199021c27325 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -827,6 +827,18 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) /* Wa4x4STCOptimizationDisable:bdw,chv */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); + /* + * BSpec recommends 8x4 when MSAA is used, + * however in practice 16x4 seems fastest. + * + * Note that PS/WM thread counts depend on the WIZ hashing + * disable bit, which we don't touch here, but it's good + * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM). + */ + WA_SET_FIELD_MASKED(GEN7_GT_MODE, + GEN6_WIZ_HASHING_MASK, + GEN6_WIZ_HASHING_16x4); + return 0; } @@ -864,18 +876,6 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */ (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); - /* - * BSpec recommends 8x4 when MSAA is used, - * however in practice 16x4 seems fastest. - * - * Note that PS/WM thread counts depend on the WIZ hashing - * disable bit, which we don't touch here, but it's good - * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM). - */ - WA_SET_FIELD_MASKED(GEN7_GT_MODE, - GEN6_WIZ_HASHING_MASK, - GEN6_WIZ_HASHING_16x4); - return 0; } @@ -905,18 +905,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) /* Improve HiZ throughput on CHV. */ WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); - /* - * BSpec recommends 8x4 when MSAA is used, - * however in practice 16x4 seems fastest. - * - * Note that PS/WM thread counts depend on the WIZ hashing - * disable bit, which we don't touch here, but it's good - * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM). - */ - WA_SET_FIELD_MASKED(GEN7_GT_MODE, - GEN6_WIZ_HASHING_MASK, - GEN6_WIZ_HASHING_16x4); - return 0; } From a340af58730e892ccb507f7a70054f7909b28d49 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:45 +0100 Subject: [PATCH 048/134] drm/i915/gen8: Move WaForceEnableNonCoherent to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 199021c27325..9b42157107e1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -814,6 +814,14 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + /* Use Force Non-Coherent whenever executing a 3D context. This is a + * workaround for for a possible hang in the unlikely event a TLB + * invalidation occurs during a PSD flush. + */ + /* WaForceEnableNonCoherent:bdw,chv */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_NON_COHERENT); + /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: * "The Hierarchical Z RAW Stall Optimization allows non-overlapping * polygons in the same 8x4 pixel/sample area to be processed without @@ -862,13 +870,7 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN8_SAMPLER_POWER_BYPASS_DIS); - /* Use Force Non-Coherent whenever executing a 3D context. This is a - * workaround for for a possible hang in the unlikely event a TLB - * invalidation occurs during a PSD flush. - */ WA_SET_BIT_MASKED(HDC_CHICKEN0, - /* WaForceEnableNonCoherent:bdw */ - HDC_FORCE_NON_COHERENT | /* WaForceContextSaveRestoreNonCoherent:bdw */ HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | /* WaHdcDisableFetchWhenMasked:bdw */ @@ -892,14 +894,8 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); - /* Use Force Non-Coherent whenever executing a 3D context. This is a - * workaround for a possible hang in the unlikely event a TLB - * invalidation occurs during a PSD flush. - */ - /* WaForceEnableNonCoherent:chv */ /* WaHdcDisableFetchWhenMasked:chv */ WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FORCE_NON_COHERENT | HDC_DONOT_FETCH_MEM_WHEN_MASKED); /* Improve HiZ throughput on CHV. */ From 120f5d28714b5c401179a1fd6010c86b13d912ff Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 25 Sep 2015 17:40:46 +0100 Subject: [PATCH 049/134] drm/i915/gen8: Move WaHdcDisableFetchWhenMasked to common init fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arun Siluvery Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9b42157107e1..c82c74caa73c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -819,7 +819,9 @@ static int gen8_init_workarounds(struct intel_engine_cs *ring) * invalidation occurs during a PSD flush. */ /* WaForceEnableNonCoherent:bdw,chv */ + /* WaHdcDisableFetchWhenMasked:bdw,chv */ WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_DONOT_FETCH_MEM_WHEN_MASKED | HDC_FORCE_NON_COHERENT); /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0: @@ -873,8 +875,6 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HDC_CHICKEN0, /* WaForceContextSaveRestoreNonCoherent:bdw */ HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | - /* WaHdcDisableFetchWhenMasked:bdw */ - HDC_DONOT_FETCH_MEM_WHEN_MASKED | /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */ (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); @@ -894,10 +894,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); - /* WaHdcDisableFetchWhenMasked:chv */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_DONOT_FETCH_MEM_WHEN_MASKED); - /* Improve HiZ throughput on CHV. */ WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); From 2d05fa16fefb9922e021e0b7db4a0c515558f103 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 28 Sep 2015 23:08:50 +0200 Subject: [PATCH 050/134] drm/i915: Fix comparison bug ->stolen->start has type u64 aka unsigned long long; relying on the difference (effectively cast to int) for sorting is wrong. It wouldn't be a problem in practice if the values compared are always within INT_MAX of each other (so that the difference is actually representable in an int), but 440fd5283a87 ("drm/mm: Support 4 GiB and larger ranges") strongly suggests that's not the case. Note: atm we don't support more than about 1G of stolen, so this is impossible currenlty. Signed-off-by: Rasmus Villemoes [danvet: Add note that this is impossible currently.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index afa79827f1f7..9839831dd6e5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -253,7 +253,11 @@ static int obj_rank_by_stolen(void *priv, struct drm_i915_gem_object *b = container_of(B, struct drm_i915_gem_object, obj_exec_link); - return a->stolen->start - b->stolen->start; + if (a->stolen->start < b->stolen->start) + return -1; + if (a->stolen->start > b->stolen->start) + return 1; + return 0; } static int i915_gem_stolen_list_info(struct seq_file *m, void *data) From 87d5d2593299cb8814e5f26c676aef3557650eea Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Thu, 24 Sep 2015 23:29:17 +0300 Subject: [PATCH 051/134] drm/i915: Renaming CCK related reg definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the DISPLAY_TRUNK_* and DISPLAY_FREQUENCY_* bits to CCK_... instead of DISPLAY_... to make it clear they apply to all CCK clock control registers. Suggested by Ville. Signed-off-by: Vandana Kannan Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 +++++----- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 59124a5714a9..aca25bf7c11e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -729,11 +729,11 @@ enum skl_disp_power_wells { #define DSI_PLL_M1_DIV_SHIFT 0 #define DSI_PLL_M1_DIV_MASK (0x1ff << 0) #define CCK_DISPLAY_CLOCK_CONTROL 0x6b -#define DISPLAY_TRUNK_FORCE_ON (1 << 17) -#define DISPLAY_TRUNK_FORCE_OFF (1 << 16) -#define DISPLAY_FREQUENCY_STATUS (0x1f << 8) -#define DISPLAY_FREQUENCY_STATUS_SHIFT 8 -#define DISPLAY_FREQUENCY_VALUES (0x1f << 0) +#define CCK_TRUNK_FORCE_ON (1 << 17) +#define CCK_TRUNK_FORCE_OFF (1 << 16) +#define CCK_FREQUENCY_STATUS (0x1f << 8) +#define CCK_FREQUENCY_STATUS_SHIFT 8 +#define CCK_FREQUENCY_VALUES (0x1f << 0) /** * DOC: DPIO diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7f3c482be1f4..36591e372db2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5807,12 +5807,12 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) /* adjust cdclk divider */ val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); - val &= ~DISPLAY_FREQUENCY_VALUES; + val &= ~CCK_FREQUENCY_VALUES; val |= divider; vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val); if (wait_for((vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL) & - DISPLAY_FREQUENCY_STATUS) == (divider << DISPLAY_FREQUENCY_STATUS_SHIFT), + CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT), 50)) DRM_ERROR("timed out waiting for CDclk change\n"); } @@ -6733,10 +6733,10 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev) val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); mutex_unlock(&dev_priv->sb_lock); - divider = val & DISPLAY_FREQUENCY_VALUES; + divider = val & CCK_FREQUENCY_VALUES; - WARN((val & DISPLAY_FREQUENCY_STATUS) != - (divider << DISPLAY_FREQUENCY_STATUS_SHIFT), + WARN((val & CCK_FREQUENCY_STATUS) != + (divider << CCK_FREQUENCY_STATUS_SHIFT), "cdclk change in progress\n"); return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1); From bfa7df01a092e92ae764d39fee07fc3f486ed6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Sep 2015 23:29:18 +0300 Subject: [PATCH 052/134] drm/i915: Read czclk from CCK on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As with the cdclk, read out czclk from CCK as well. This gives us the real current value and avoids having to decode fuses and whatnot. Also store it in kHz under dev_priv like we do for cdlck since it's not just an rps related clock, and having it in kHz is more standard/convenient for some things. Imre also pointed out that we currently fail to read czclk on VLV, which means the PFI credit programming isn't working as expected. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 88 +++++++++++++++++----------- drivers/gpu/drm/i915/intel_pm.c | 25 ++------ 4 files changed, 60 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ad37b2591878..4711a79cb57d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1146,7 +1146,6 @@ struct intel_gen6_power_mgmt { u8 efficient_freq; /* AKA RPe. Pre-determined balanced frequency */ u8 rp1_freq; /* "less than" RP0 power/freqency */ u8 rp0_freq; /* Non-overclocked max frequency. */ - u32 cz_freq; u8 up_threshold; /* Current %busy required to uplock */ u8 down_threshold; /* Current %busy required to downclock */ @@ -1810,6 +1809,7 @@ struct drm_i915_private { unsigned int cdclk_freq, max_cdclk_freq; unsigned int max_dotclk_freq; unsigned int hpll_freq; + unsigned int czclk_freq; /** * wq - Driver workqueue for GEM. diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aca25bf7c11e..3709d6b2559f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -728,6 +728,7 @@ enum skl_disp_power_wells { #define DSI_PLL_N1_DIV_MASK (3 << 16) #define DSI_PLL_M1_DIV_SHIFT 0 #define DSI_PLL_M1_DIV_MASK (0x1ff << 0) +#define CCK_CZ_CLOCK_CONTROL 0x62 #define CCK_DISPLAY_CLOCK_CONTROL 0x6b #define CCK_TRUNK_FORCE_ON (1 << 17) #define CCK_TRUNK_FORCE_OFF (1 << 16) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36591e372db2..797b8825c133 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -132,6 +132,42 @@ struct intel_limit { intel_p2_t p2; }; +/* returns HPLL frequency in kHz */ +static int valleyview_get_vco(struct drm_i915_private *dev_priv) +{ + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + + /* Obtain SKU information */ + mutex_lock(&dev_priv->sb_lock); + hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + mutex_unlock(&dev_priv->sb_lock); + + return vco_freq[hpll_freq] * 1000; +} + +static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv, + const char *name, u32 reg) +{ + u32 val; + int divider; + + if (dev_priv->hpll_freq == 0) + dev_priv->hpll_freq = valleyview_get_vco(dev_priv); + + mutex_lock(&dev_priv->sb_lock); + val = vlv_cck_read(dev_priv, reg); + mutex_unlock(&dev_priv->sb_lock); + + divider = val & CCK_FREQUENCY_VALUES; + + WARN((val & CCK_FREQUENCY_STATUS) != + (divider << CCK_FREQUENCY_STATUS_SHIFT), + "%s change in progress\n", name); + + return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1); +} + int intel_pch_rawclk(struct drm_device *dev) { @@ -175,6 +211,17 @@ int intel_hrawclk(struct drm_device *dev) } } +static void intel_update_czclk(struct drm_i915_private *dev_priv) +{ + if (!IS_VALLEYVIEW(dev_priv)) + return; + + dev_priv->czclk_freq = vlv_get_cck_clock_hpll(dev_priv, "czclk", + CCK_CZ_CLOCK_CONTROL); + + DRM_DEBUG_DRIVER("CZ clock rate: %d kHz\n", dev_priv->czclk_freq); +} + static inline u32 /* units of 100MHz */ intel_fdi_link_freq(struct drm_device *dev) { @@ -5756,20 +5803,6 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) DRM_ERROR("DBuf power enable timeout\n"); } -/* returns HPLL frequency in kHz */ -static int valleyview_get_vco(struct drm_i915_private *dev_priv) -{ - int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - - /* Obtain SKU information */ - mutex_lock(&dev_priv->sb_lock); - hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & - CCK_FUSE_HPLL_FREQ_MASK; - mutex_unlock(&dev_priv->sb_lock); - - return vco_freq[hpll_freq] * 1000; -} - /* Adjust CDclk dividers to allow high res or save power if possible */ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) { @@ -5990,7 +6023,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) else default_credits = PFI_CREDIT(8); - if (DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 1000) >= dev_priv->rps.cz_freq) { + if (dev_priv->cdclk_freq >= dev_priv->czclk_freq) { /* CHV suggested value is 31 or 63 */ if (IS_CHERRYVIEW(dev_priv)) credits = PFI_CREDIT_63; @@ -6722,24 +6755,8 @@ static int haswell_get_display_clock_speed(struct drm_device *dev) static int valleyview_get_display_clock_speed(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - int divider; - - if (dev_priv->hpll_freq == 0) - dev_priv->hpll_freq = valleyview_get_vco(dev_priv); - - mutex_lock(&dev_priv->sb_lock); - val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); - mutex_unlock(&dev_priv->sb_lock); - - divider = val & CCK_FREQUENCY_VALUES; - - WARN((val & CCK_FREQUENCY_STATUS) != - (divider << CCK_FREQUENCY_STATUS_SHIFT), - "cdclk change in progress\n"); - - return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1); + return vlv_get_cck_clock_hpll(to_i915(dev), "cdclk", + CCK_DISPLAY_CLOCK_CONTROL); } static int ilk_get_display_clock_speed(struct drm_device *dev) @@ -13329,8 +13346,6 @@ static void intel_shared_dpll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - intel_update_cdclk(dev); - if (HAS_DDI(dev)) intel_ddi_pll_init(dev); else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) @@ -14839,6 +14854,9 @@ void intel_modeset_init(struct drm_device *dev) } } + intel_update_czclk(dev_priv); + intel_update_cdclk(dev); + intel_shared_dpll_init(dev); /* Just disable it once at startup */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 780b1e01d333..9643a7c433d8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5460,25 +5460,10 @@ static void cherryview_init_gt_powersave(struct drm_device *dev) mutex_unlock(&dev_priv->sb_lock); switch ((val >> 2) & 0x7) { - case 0: - case 1: - dev_priv->rps.cz_freq = 200; - dev_priv->mem_freq = 1600; - break; - case 2: - dev_priv->rps.cz_freq = 267; - dev_priv->mem_freq = 1600; - break; case 3: - dev_priv->rps.cz_freq = 333; dev_priv->mem_freq = 2000; break; - case 4: - dev_priv->rps.cz_freq = 320; - dev_priv->mem_freq = 1600; - break; - case 5: - dev_priv->rps.cz_freq = 400; + default: dev_priv->mem_freq = 1600; break; } @@ -7305,7 +7290,7 @@ static int vlv_gpu_freq_div(unsigned int czclk_freq) static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val) { - int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->mem_freq, 4); + int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); div = vlv_gpu_freq_div(czclk_freq); if (div < 0) @@ -7316,7 +7301,7 @@ static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val) static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val) { - int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->mem_freq, 4); + int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); mul = vlv_gpu_freq_div(czclk_freq); if (mul < 0) @@ -7327,7 +7312,7 @@ static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val) static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val) { - int div, czclk_freq = dev_priv->rps.cz_freq; + int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); div = vlv_gpu_freq_div(czclk_freq) / 2; if (div < 0) @@ -7338,7 +7323,7 @@ static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val) static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val) { - int mul, czclk_freq = dev_priv->rps.cz_freq; + int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); mul = vlv_gpu_freq_div(czclk_freq) / 2; if (mul < 0) From 2cc9fab180e8add4159ed1fc874131f984d0bcb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 28 Sep 2015 23:43:43 +0300 Subject: [PATCH 053/134] drm/i915: Simplify vlv/chv rc6 residency calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the czclk frequency in dev_priv now, so let's just use it when converting the rc6 counters to milliseconds. This eliminates a bunch of hairy code that essentially tries to extract the czclk frequency using yet another method. v2: Fix typos in commit message (Imre) Reviewed-by: Imre Deak Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 55bd04c6b939..74086eb5bf83 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -39,7 +39,7 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) { struct drm_i915_private *dev_priv = dev->dev_private; u64 raw_time; /* 32b value may overflow during fixed point math */ - u64 units = 128ULL, div = 100000ULL, bias = 100ULL; + u64 units = 128ULL, div = 100000ULL; u32 ret; if (!intel_enable_rc6(dev)) @@ -49,41 +49,16 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) /* On VLV and CHV, residency time is in CZ units rather than 1.28us */ if (IS_VALLEYVIEW(dev)) { - u32 clk_reg, czcount_30ns; - - if (IS_CHERRYVIEW(dev)) - clk_reg = CHV_CLK_CTL1; - else - clk_reg = VLV_CLK_CTL2; - - czcount_30ns = I915_READ(clk_reg) >> CLK_CTL2_CZCOUNT_30NS_SHIFT; - - if (!czcount_30ns) { - WARN(!czcount_30ns, "bogus CZ count value"); - ret = 0; - goto out; - } - - if (IS_CHERRYVIEW(dev) && czcount_30ns == 1) { - /* Special case for 320Mhz */ - div = 10000000ULL; - units = 3125ULL; - } else { - czcount_30ns += 1; - div = 1000000ULL; - units = DIV_ROUND_UP_ULL(30ULL * bias, czcount_30ns); - } + units = 1; + div = dev_priv->czclk_freq; if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) units <<= 8; - - div = div * bias; } raw_time = I915_READ(reg) * units; ret = DIV_ROUND_UP_ULL(raw_time, div); -out: intel_runtime_pm_put(dev_priv); return ret; } From 7bad74d57c81b08218cc564af3a78427e12bf3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Sep 2015 23:29:20 +0300 Subject: [PATCH 054/134] drm/i915: Use czclk_freq in vlv c0 residency calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the use of mem_freq/4 with czclk_freq in the vlv c0 residency calculations. Also deal with VLV_COUNT_RANGE_HIGH which affects all RCx residency counters. We have just enough bits to do this without intermediate divisions. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ff85eae932bc..76bd40e13391 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -997,12 +997,16 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv, int threshold) { u64 time, c0; + unsigned int mul = 100; if (old->cz_clock == 0) return false; + if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) + mul <<= 8; + time = now->cz_clock - old->cz_clock; - time *= threshold * dev_priv->mem_freq; + time *= threshold * dev_priv->czclk_freq; /* Workload can be split between render + media, e.g. SwapBuffers * being blitted in X after being rendered in mesa. To account for @@ -1010,7 +1014,7 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv, */ c0 = now->render_c0 - old->render_c0; c0 += now->media_c0 - old->media_c0; - c0 *= 100 * VLV_CZ_CLOCK_TO_MILLI_SEC * 4 / 1000; + c0 *= mul * VLV_CZ_CLOCK_TO_MILLI_SEC; return c0 >= time; } From 85b98a4c30c60272b2830d9acc43121eb2988bd2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 29 Sep 2015 10:24:25 +0300 Subject: [PATCH 055/134] drm/i915/ddi: warn instead of oops on invalid ddi encoder type It's more useful to limp on than bring the kernel down. Hitting this is a more likely event with BXT DSI, although care should be taken not to call the function for DSI. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 0e46679fde5a..fdcb4562c8ce 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -322,8 +322,7 @@ static void ddi_get_encoder_port(struct intel_encoder *intel_encoder, *dig_port = NULL; *port = PORT_E; } else { - DRM_ERROR("Invalid DDI encoder type %d\n", type); - BUG(); + WARN(1, "Invalid DDI encoder type %d\n", type); } } From 8cd21b7f28ed1f12059935512edaaadf1deaeb67 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 29 Sep 2015 10:24:26 +0300 Subject: [PATCH 056/134] drm/i915/ddi: use switch case instead of if ladder for ddi_get_encoder_port Make the alternatives stand out better. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index fdcb4562c8ce..2b5a29817e2e 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -309,20 +309,26 @@ static void ddi_get_encoder_port(struct intel_encoder *intel_encoder, enum port *port) { struct drm_encoder *encoder = &intel_encoder->base; - int type = intel_encoder->type; - if (type == INTEL_OUTPUT_DP_MST) { + switch (intel_encoder->type) { + case INTEL_OUTPUT_DP_MST: *dig_port = enc_to_mst(encoder)->primary; *port = (*dig_port)->port; - } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || - type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { + break; + case INTEL_OUTPUT_DISPLAYPORT: + case INTEL_OUTPUT_EDP: + case INTEL_OUTPUT_HDMI: + case INTEL_OUTPUT_UNKNOWN: *dig_port = enc_to_dig_port(encoder); *port = (*dig_port)->port; - } else if (type == INTEL_OUTPUT_ANALOG) { + break; + case INTEL_OUTPUT_ANALOG: *dig_port = NULL; *port = PORT_E; - } else { - WARN(1, "Invalid DDI encoder type %d\n", type); + break; + default: + WARN(1, "Invalid DDI encoder type %d\n", intel_encoder->type); + break; } } From 5507faeb03f87f952373314b21741548421a6944 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 14 Sep 2015 14:03:48 +0300 Subject: [PATCH 057/134] drm/i915: make backlight hooks connector specific Previously we've relied on having basically one backlight and one backlight type per platform. This is already a bit quirky with PMIC PWM support on VLV/CHV platforms with MIPI DSI. In the foreseeable future we'll have at least DPCD based backlight control on eDP and DCS command based backlight control on MIPI DSI. Backlight is becoming more and more connector specific, so reflect this fact by making the backlight control hooks connector specific. This enables further work to reuse generic backlight code in intel_panel.c while adding more specific backlight code accessed via the hooks. Cc: Deepak M Cc: Yetunde Adebisi Signed-off-by: Jani Nikula Reviewed-by: Deepak M Reviewed-by: Yetunde Adebisi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 9 --- drivers/gpu/drm/i915/intel_display.c | 2 - drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 13 ++- drivers/gpu/drm/i915/intel_panel.c | 116 +++++++++++++++------------ 5 files changed, 74 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4711a79cb57d..ee478acc0a5b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -664,15 +664,6 @@ struct drm_i915_display_funcs { /* render clock increase/decrease */ /* display clock increase/decrease */ /* pll clock increase/decrease */ - - int (*setup_backlight)(struct intel_connector *connector, enum pipe pipe); - uint32_t (*get_backlight)(struct intel_connector *connector); - void (*set_backlight)(struct intel_connector *connector, - uint32_t level); - void (*disable_backlight)(struct intel_connector *connector); - void (*enable_backlight)(struct intel_connector *connector); - uint32_t (*backlight_hz_to_pwm)(struct intel_connector *connector, - uint32_t hz); }; enum forcewake_domain_id { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 797b8825c133..8e4fb80497a1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14575,8 +14575,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.queue_flip = intel_default_queue_flip; } - intel_panel_init_backlight_funcs(dev); - mutex_init(&dev_priv->pps_mutex); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 77f733007e32..97ed418060ff 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6000,7 +6000,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); - intel_connector->panel.backlight_power = intel_edp_backlight_power; + intel_connector->panel.backlight.power = intel_edp_backlight_power; intel_panel_setup_backlight(connector, pipe); return true; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ed66a4f26dbd..1eaa9f91bcb7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -182,9 +182,17 @@ struct intel_panel { struct pwm_device *pwm; struct backlight_device *device; - } backlight; - void (*backlight_power)(struct intel_connector *, bool enable); + /* Connector and platform specific backlight functions */ + int (*setup)(struct intel_connector *connector, enum pipe pipe); + uint32_t (*get)(struct intel_connector *connector); + void (*set)(struct intel_connector *connector, uint32_t level); + void (*disable)(struct intel_connector *connector); + void (*enable)(struct intel_connector *connector); + uint32_t (*hz_to_pwm)(struct intel_connector *connector, + uint32_t hz); + void (*power)(struct intel_connector *, bool enable); + } backlight; }; struct intel_connector { @@ -1333,7 +1341,6 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) void intel_panel_enable_backlight(struct intel_connector *connector); void intel_panel_disable_backlight(struct intel_connector *connector); void intel_panel_destroy_backlight(struct drm_connector *connector); -void intel_panel_init_backlight_funcs(struct drm_device *dev); enum drm_connector_status intel_panel_detect(struct drm_device *dev); extern struct drm_display_mode *intel_find_panel_downclock( struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index dd71e7f139e3..4d28c7b904e7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -560,7 +560,7 @@ static u32 intel_panel_get_backlight(struct intel_connector *connector) mutex_lock(&dev_priv->backlight_lock); if (panel->backlight.enabled) { - val = dev_priv->display.get_backlight(connector); + val = panel->backlight.get(connector); val = intel_panel_compute_brightness(connector, val); } @@ -649,13 +649,12 @@ static void pwm_set_backlight(struct intel_connector *connector, u32 level) static void intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) { - struct drm_device *dev = connector->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); level = intel_panel_compute_brightness(connector, level); - dev_priv->display.set_backlight(connector, level); + panel->backlight.set(connector, level); } /* set backlight brightness to level in range [0..max], scaling wrt hw min */ @@ -830,7 +829,7 @@ void intel_panel_disable_backlight(struct intel_connector *connector) if (panel->backlight.device) panel->backlight.device->props.power = FB_BLANK_POWERDOWN; panel->backlight.enabled = false; - dev_priv->display.disable_backlight(connector); + panel->backlight.disable(connector); mutex_unlock(&dev_priv->backlight_lock); } @@ -1079,7 +1078,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector) panel->backlight.device->props.max_brightness); } - dev_priv->display.enable_backlight(connector); + panel->backlight.enable(connector); panel->backlight.enabled = true; if (panel->backlight.device) panel->backlight.device->props.power = FB_BLANK_UNBLANK; @@ -1107,10 +1106,10 @@ static int intel_backlight_device_update_status(struct backlight_device *bd) * callback needs to take this into account. */ if (panel->backlight.enabled) { - if (panel->backlight_power) { + if (panel->backlight.power) { bool enable = bd->props.power == FB_BLANK_UNBLANK && bd->props.brightness != 0; - panel->backlight_power(connector, enable); + panel->backlight.power(connector, enable); } } else { bd->props.power = FB_BLANK_POWERDOWN; @@ -1335,6 +1334,7 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; u32 pwm; @@ -1343,12 +1343,12 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector) return 0; } - if (!dev_priv->display.backlight_hz_to_pwm) { + if (!panel->backlight.hz_to_pwm) { DRM_DEBUG_KMS("backlight frequency setting from VBT currently not supported on this platform\n"); return 0; } - pwm = dev_priv->display.backlight_hz_to_pwm(connector, pwm_freq_hz); + pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz); if (!pwm) { DRM_DEBUG_KMS("backlight frequency conversion failed\n"); return 0; @@ -1633,9 +1633,13 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) } } + /* ensure intel_panel has been initialized first */ + if (WARN_ON(!panel->backlight.setup)) + return -ENODEV; + /* set level and max in panel struct */ mutex_lock(&dev_priv->backlight_lock); - ret = dev_priv->display.setup_backlight(intel_connector, pipe); + ret = panel->backlight.setup(intel_connector, pipe); mutex_unlock(&dev_priv->backlight_lock); if (ret) { @@ -1667,62 +1671,66 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) } /* Set up chip specific backlight functions */ -void intel_panel_init_backlight_funcs(struct drm_device *dev) +static void +intel_panel_init_backlight_funcs(struct intel_panel *panel) { + struct intel_connector *intel_connector = + container_of(panel, struct intel_connector, panel); + struct drm_device *dev = intel_connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; if (IS_BROXTON(dev)) { - dev_priv->display.setup_backlight = bxt_setup_backlight; - dev_priv->display.enable_backlight = bxt_enable_backlight; - dev_priv->display.disable_backlight = bxt_disable_backlight; - dev_priv->display.set_backlight = bxt_set_backlight; - dev_priv->display.get_backlight = bxt_get_backlight; + panel->backlight.setup = bxt_setup_backlight; + panel->backlight.enable = bxt_enable_backlight; + panel->backlight.disable = bxt_disable_backlight; + panel->backlight.set = bxt_set_backlight; + panel->backlight.get = bxt_get_backlight; } else if (HAS_PCH_LPT(dev) || HAS_PCH_SPT(dev)) { - dev_priv->display.setup_backlight = lpt_setup_backlight; - dev_priv->display.enable_backlight = lpt_enable_backlight; - dev_priv->display.disable_backlight = lpt_disable_backlight; - dev_priv->display.set_backlight = lpt_set_backlight; - dev_priv->display.get_backlight = lpt_get_backlight; + panel->backlight.setup = lpt_setup_backlight; + panel->backlight.enable = lpt_enable_backlight; + panel->backlight.disable = lpt_disable_backlight; + panel->backlight.set = lpt_set_backlight; + panel->backlight.get = lpt_get_backlight; if (HAS_PCH_LPT(dev)) - dev_priv->display.backlight_hz_to_pwm = lpt_hz_to_pwm; + panel->backlight.hz_to_pwm = lpt_hz_to_pwm; else - dev_priv->display.backlight_hz_to_pwm = spt_hz_to_pwm; + panel->backlight.hz_to_pwm = spt_hz_to_pwm; } else if (HAS_PCH_SPLIT(dev)) { - dev_priv->display.setup_backlight = pch_setup_backlight; - dev_priv->display.enable_backlight = pch_enable_backlight; - dev_priv->display.disable_backlight = pch_disable_backlight; - dev_priv->display.set_backlight = pch_set_backlight; - dev_priv->display.get_backlight = pch_get_backlight; - dev_priv->display.backlight_hz_to_pwm = pch_hz_to_pwm; + panel->backlight.setup = pch_setup_backlight; + panel->backlight.enable = pch_enable_backlight; + panel->backlight.disable = pch_disable_backlight; + panel->backlight.set = pch_set_backlight; + panel->backlight.get = pch_get_backlight; + panel->backlight.hz_to_pwm = pch_hz_to_pwm; } else if (IS_VALLEYVIEW(dev)) { if (dev_priv->vbt.has_mipi) { - dev_priv->display.setup_backlight = pwm_setup_backlight; - dev_priv->display.enable_backlight = pwm_enable_backlight; - dev_priv->display.disable_backlight = pwm_disable_backlight; - dev_priv->display.set_backlight = pwm_set_backlight; - dev_priv->display.get_backlight = pwm_get_backlight; + panel->backlight.setup = pwm_setup_backlight; + panel->backlight.enable = pwm_enable_backlight; + panel->backlight.disable = pwm_disable_backlight; + panel->backlight.set = pwm_set_backlight; + panel->backlight.get = pwm_get_backlight; } else { - dev_priv->display.setup_backlight = vlv_setup_backlight; - dev_priv->display.enable_backlight = vlv_enable_backlight; - dev_priv->display.disable_backlight = vlv_disable_backlight; - dev_priv->display.set_backlight = vlv_set_backlight; - dev_priv->display.get_backlight = vlv_get_backlight; - dev_priv->display.backlight_hz_to_pwm = vlv_hz_to_pwm; + panel->backlight.setup = vlv_setup_backlight; + panel->backlight.enable = vlv_enable_backlight; + panel->backlight.disable = vlv_disable_backlight; + panel->backlight.set = vlv_set_backlight; + panel->backlight.get = vlv_get_backlight; + panel->backlight.hz_to_pwm = vlv_hz_to_pwm; } } else if (IS_GEN4(dev)) { - dev_priv->display.setup_backlight = i965_setup_backlight; - dev_priv->display.enable_backlight = i965_enable_backlight; - dev_priv->display.disable_backlight = i965_disable_backlight; - dev_priv->display.set_backlight = i9xx_set_backlight; - dev_priv->display.get_backlight = i9xx_get_backlight; - dev_priv->display.backlight_hz_to_pwm = i965_hz_to_pwm; + panel->backlight.setup = i965_setup_backlight; + panel->backlight.enable = i965_enable_backlight; + panel->backlight.disable = i965_disable_backlight; + panel->backlight.set = i9xx_set_backlight; + panel->backlight.get = i9xx_get_backlight; + panel->backlight.hz_to_pwm = i965_hz_to_pwm; } else { - dev_priv->display.setup_backlight = i9xx_setup_backlight; - dev_priv->display.enable_backlight = i9xx_enable_backlight; - dev_priv->display.disable_backlight = i9xx_disable_backlight; - dev_priv->display.set_backlight = i9xx_set_backlight; - dev_priv->display.get_backlight = i9xx_get_backlight; - dev_priv->display.backlight_hz_to_pwm = i9xx_hz_to_pwm; + panel->backlight.setup = i9xx_setup_backlight; + panel->backlight.enable = i9xx_enable_backlight; + panel->backlight.disable = i9xx_disable_backlight; + panel->backlight.set = i9xx_set_backlight; + panel->backlight.get = i9xx_get_backlight; + panel->backlight.hz_to_pwm = i9xx_hz_to_pwm; } } @@ -1730,6 +1738,8 @@ int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, struct drm_display_mode *downclock_mode) { + intel_panel_init_backlight_funcs(panel); + panel->fixed_mode = fixed_mode; panel->downclock_mode = downclock_mode; From 76b1cf211cbe120a2d6c46403abc97d4376c619e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Sep 2015 14:15:25 +0200 Subject: [PATCH 058/134] drm: i915: drop null test before destroy functions Remove unneeded NULL test. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; @@ -if (x != NULL) \(kmem_cache_destroy\|mempool_destroy\|dma_pool_destroy\)(x); // Signed-off-by: Julia Lawall Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 817b05ce8dd3..ae1ba47e4ef0 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1074,12 +1074,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) put_bridge: pci_dev_put(dev_priv->bridge_dev); free_priv: - if (dev_priv->requests) - kmem_cache_destroy(dev_priv->requests); - if (dev_priv->vmas) - kmem_cache_destroy(dev_priv->vmas); - if (dev_priv->objects) - kmem_cache_destroy(dev_priv->objects); + kmem_cache_destroy(dev_priv->requests); + kmem_cache_destroy(dev_priv->vmas); + kmem_cache_destroy(dev_priv->objects); kfree(dev_priv); return ret; } @@ -1170,13 +1167,9 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->regs != NULL) pci_iounmap(dev->pdev, dev_priv->regs); - if (dev_priv->requests) - kmem_cache_destroy(dev_priv->requests); - if (dev_priv->vmas) - kmem_cache_destroy(dev_priv->vmas); - if (dev_priv->objects) - kmem_cache_destroy(dev_priv->objects); - + kmem_cache_destroy(dev_priv->requests); + kmem_cache_destroy(dev_priv->vmas); + kmem_cache_destroy(dev_priv->objects); pci_dev_put(dev_priv->bridge_dev); kfree(dev_priv); From 91bedd34abf0cd3f6276de642a145f75731acca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Daniluk?= Date: Fri, 25 Sep 2015 11:54:58 +0200 Subject: [PATCH 059/134] drm/i915/bdw: Check for slice, subslice and EU count for BDW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added checks for available slices, subslices and EUs for Broadwell. This information is filled in intel_device_info and is available to user with GET_PARAM. Added checks for enabled slices, subslices and EU for Broadwell. This information is based on available counts but takes power gated slices into account. It can be read in debugfs. Introduce new register defines that contain information on slices on Broadwell. v2: - Introduce GT_SLICE_INFO register - Change Broadwell sseu_device_status function to use GT_SLICE_INFO register instead of RPCS register - Undo removal of dev_priv variables in Cherryview and Gen9 sseu_device_satus functions v3: - Fix style issues v4: - Corrected comment - Reverted reordering of defines Cc: Jeff Mcgee Cc: Arun Siluvery Signed-off-by: Łukasz Daniluk Reviewed-by: Jeff McGee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 29 ++++++++++- drivers/gpu/drm/i915/i915_dma.c | 78 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 18 +++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9839831dd6e5..2ac1ba813593 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -5048,13 +5048,38 @@ static void gen9_sseu_device_status(struct drm_device *dev, } } +static void broadwell_sseu_device_status(struct drm_device *dev, + struct sseu_dev_status *stat) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int s; + u32 slice_info = I915_READ(GEN8_GT_SLICE_INFO); + + stat->slice_total = hweight32(slice_info & GEN8_LSLICESTAT_MASK); + + if (stat->slice_total) { + stat->subslice_per_slice = INTEL_INFO(dev)->subslice_per_slice; + stat->subslice_total = stat->slice_total * + stat->subslice_per_slice; + stat->eu_per_subslice = INTEL_INFO(dev)->eu_per_subslice; + stat->eu_total = stat->eu_per_subslice * stat->subslice_total; + + /* subtract fused off EU(s) from enabled slice(s) */ + for (s = 0; s < stat->slice_total; s++) { + u8 subslice_7eu = INTEL_INFO(dev)->subslice_7eu[s]; + + stat->eu_total -= hweight8(subslice_7eu); + } + } +} + static int i915_sseu_status(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct sseu_dev_status stat; - if ((INTEL_INFO(dev)->gen < 8) || IS_BROADWELL(dev)) + if (INTEL_INFO(dev)->gen < 8) return -ENODEV; seq_puts(m, "SSEU Device Info\n"); @@ -5079,6 +5104,8 @@ static int i915_sseu_status(struct seq_file *m, void *unused) memset(&stat, 0, sizeof(stat)); if (IS_CHERRYVIEW(dev)) { cherryview_sseu_device_status(dev, &stat); + } else if (IS_BROADWELL(dev)) { + broadwell_sseu_device_status(dev, &stat); } else if (INTEL_INFO(dev)->gen >= 9) { gen9_sseu_device_status(dev, &stat); } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ae1ba47e4ef0..20b4b7924f51 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -702,6 +702,82 @@ static void gen9_sseu_info_init(struct drm_device *dev) info->has_eu_pg = (info->eu_per_subslice > 2); } +static void broadwell_sseu_info_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_device_info *info; + const int s_max = 3, ss_max = 3, eu_max = 8; + int s, ss; + u32 fuse2, eu_disable[s_max], s_enable, ss_disable; + + fuse2 = I915_READ(GEN8_FUSE2); + s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT; + ss_disable = (fuse2 & GEN8_F2_SS_DIS_MASK) >> GEN8_F2_SS_DIS_SHIFT; + + eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK; + eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) | + ((I915_READ(GEN8_EU_DISABLE1) & GEN8_EU_DIS1_S1_MASK) << + (32 - GEN8_EU_DIS0_S1_SHIFT)); + eu_disable[2] = (I915_READ(GEN8_EU_DISABLE1) >> GEN8_EU_DIS1_S2_SHIFT) | + ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) << + (32 - GEN8_EU_DIS1_S2_SHIFT)); + + + info = (struct intel_device_info *)&dev_priv->info; + info->slice_total = hweight32(s_enable); + + /* + * The subslice disable field is global, i.e. it applies + * to each of the enabled slices. + */ + info->subslice_per_slice = ss_max - hweight32(ss_disable); + info->subslice_total = info->slice_total * info->subslice_per_slice; + + /* + * Iterate through enabled slices and subslices to + * count the total enabled EU. + */ + for (s = 0; s < s_max; s++) { + if (!(s_enable & (0x1 << s))) + /* skip disabled slice */ + continue; + + for (ss = 0; ss < ss_max; ss++) { + u32 n_disabled; + + if (ss_disable & (0x1 << ss)) + /* skip disabled subslice */ + continue; + + n_disabled = hweight8(eu_disable[s] >> (ss * eu_max)); + + /* + * Record which subslices have 7 EUs. + */ + if (eu_max - n_disabled == 7) + info->subslice_7eu[s] |= 1 << ss; + + info->eu_total += eu_max - n_disabled; + } + } + + /* + * BDW is expected to always have a uniform distribution of EU across + * subslices with the exception that any one EU in any one subslice may + * be fused off for die recovery. + */ + info->eu_per_subslice = info->subslice_total ? + DIV_ROUND_UP(info->eu_total, info->subslice_total) : 0; + + /* + * BDW supports slice power gating on devices with more than + * one slice. + */ + info->has_slice_pg = (info->slice_total > 1); + info->has_subslice_pg = 0; + info->has_eu_pg = 0; +} + /* * Determine various intel_device_info fields at runtime. * @@ -772,6 +848,8 @@ static void intel_device_info_runtime_init(struct drm_device *dev) /* Initialize slice/subslice/EU info */ if (IS_CHERRYVIEW(dev)) cherryview_sseu_info_init(dev); + else if (IS_BROADWELL(dev)) + broadwell_sseu_info_init(dev); else if (INTEL_INFO(dev)->gen >= 9) gen9_sseu_info_init(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3709d6b2559f..0b2e3148a5bf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1887,12 +1887,27 @@ enum skl_disp_power_wells { #define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT) #define GEN8_FUSE2 0x9120 +#define GEN8_F2_SS_DIS_SHIFT 21 +#define GEN8_F2_SS_DIS_MASK (0x7 << GEN8_F2_SS_DIS_SHIFT) #define GEN8_F2_S_ENA_SHIFT 25 #define GEN8_F2_S_ENA_MASK (0x7 << GEN8_F2_S_ENA_SHIFT) #define GEN9_F2_SS_DIS_SHIFT 20 #define GEN9_F2_SS_DIS_MASK (0xf << GEN9_F2_SS_DIS_SHIFT) +#define GEN8_EU_DISABLE0 0x9134 +#define GEN8_EU_DIS0_S0_MASK 0xffffff +#define GEN8_EU_DIS0_S1_SHIFT 24 +#define GEN8_EU_DIS0_S1_MASK (0xff << GEN8_EU_DIS0_S1_SHIFT) + +#define GEN8_EU_DISABLE1 0x9138 +#define GEN8_EU_DIS1_S1_MASK 0xffff +#define GEN8_EU_DIS1_S2_SHIFT 16 +#define GEN8_EU_DIS1_S2_MASK (0xffff << GEN8_EU_DIS1_S2_SHIFT) + +#define GEN8_EU_DISABLE2 0x913c +#define GEN8_EU_DIS2_S2_MASK 0xff + #define GEN9_EU_DISABLE(slice) (0x9134 + (slice)*0x4) #define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 @@ -6885,6 +6900,9 @@ enum skl_disp_power_wells { #define GEN6_RC6 3 #define GEN6_RC7 4 +#define GEN8_GT_SLICE_INFO 0x138064 +#define GEN8_LSLICESTAT_MASK 0x7 + #define CHV_POWER_SS0_SIG1 0xa720 #define CHV_POWER_SS1_SIG1 0xa728 #define CHV_SS_PG_ENABLE (1<<1) From 87f77eff710db012a994ee319b5627c26a7b2204 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Sep 2015 09:39:01 +0200 Subject: [PATCH 060/134] drm/i915: Add missing const to audio_rate_need_prog() The lack of const leads to a compile warning after merging i915 upstream tree: drivers/gpu/drm/i915/intel_audio.c:147:13: note: expected 'struct drm_display_mode *' but argument is of type 'const struct drm_display_mode *' Reported-by: kbuild test robot Reviewed-by: Daniel Vetter Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 30f6859dcb36..dffd0b4c5f17 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -144,7 +144,7 @@ static uint32_t audio_config_setup_n_reg(int n, uint32_t val) /* check whether N/CTS/M need be set manually */ static bool audio_rate_need_prog(struct intel_crtc *crtc, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (((mode->clock == TMDS_297M) || (mode->clock == TMDS_296M)) && From eede3b53e9b5f7587e876ae9575392f92932951a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:30 +0300 Subject: [PATCH 061/134] drm/i915: s/_FDI_RXA_.../FDI_RX_...(PIPE_A)/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_ddi.c | 46 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index cac7928ebc49..b84aaa0bb48a 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -890,7 +890,7 @@ void intel_crt_init(struct drm_device *dev) u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT | FDI_RX_LINK_REVERSAL_OVERRIDE; - dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config; + dev_priv->fdi_rx_config = I915_READ(FDI_RX_CTL(PIPE_A)) & fdi_config; } intel_crt_reset(connector); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 2b5a29817e2e..9c115773ef4b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -608,7 +608,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) * * WaFDIAutoLinkSetTimingOverrride:hsw */ - I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | + I915_WRITE(FDI_RX_MISC(PIPE_A), FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); @@ -616,13 +616,13 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | FDI_RX_PLL_ENABLE | FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes); - I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); - POSTING_READ(_FDI_RXA_CTL); + I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val); + POSTING_READ(FDI_RX_CTL(PIPE_A)); udelay(220); /* Switch from Rawclk to PCDclk */ rx_ctl_val |= FDI_PCDCLK; - I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); + I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val); /* Configure Port Clock Select */ I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel); @@ -651,21 +651,21 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) udelay(600); /* Program PCH FDI Receiver TU */ - I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64)); + I915_WRITE(FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64)); /* Enable PCH FDI Receiver with auto-training */ rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; - I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); - POSTING_READ(_FDI_RXA_CTL); + I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val); + POSTING_READ(FDI_RX_CTL(PIPE_A)); /* Wait for FDI receiver lane calibration */ udelay(30); /* Unset FDI_RX_MISC pwrdn lanes */ - temp = I915_READ(_FDI_RXA_MISC); + temp = I915_READ(FDI_RX_MISC(PIPE_A)); temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); - I915_WRITE(_FDI_RXA_MISC, temp); - POSTING_READ(_FDI_RXA_MISC); + I915_WRITE(FDI_RX_MISC(PIPE_A), temp); + POSTING_READ(FDI_RX_MISC(PIPE_A)); /* Wait for FDI auto training time */ udelay(5); @@ -699,15 +699,15 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) intel_wait_ddi_buf_idle(dev_priv, PORT_E); rx_ctl_val &= ~FDI_RX_ENABLE; - I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); - POSTING_READ(_FDI_RXA_CTL); + I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val); + POSTING_READ(FDI_RX_CTL(PIPE_A)); /* Reset FDI_RX_MISC pwrdn lanes */ - temp = I915_READ(_FDI_RXA_MISC); + temp = I915_READ(FDI_RX_MISC(PIPE_A)); temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); - I915_WRITE(_FDI_RXA_MISC, temp); - POSTING_READ(_FDI_RXA_MISC); + I915_WRITE(FDI_RX_MISC(PIPE_A), temp); + POSTING_READ(FDI_RX_MISC(PIPE_A)); } DRM_ERROR("FDI link training failed!\n"); @@ -3023,22 +3023,22 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc) intel_ddi_post_disable(intel_encoder); - val = I915_READ(_FDI_RXA_CTL); + val = I915_READ(FDI_RX_CTL(PIPE_A)); val &= ~FDI_RX_ENABLE; - I915_WRITE(_FDI_RXA_CTL, val); + I915_WRITE(FDI_RX_CTL(PIPE_A), val); - val = I915_READ(_FDI_RXA_MISC); + val = I915_READ(FDI_RX_MISC(PIPE_A)); val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); - I915_WRITE(_FDI_RXA_MISC, val); + I915_WRITE(FDI_RX_MISC(PIPE_A), val); - val = I915_READ(_FDI_RXA_CTL); + val = I915_READ(FDI_RX_CTL(PIPE_A)); val &= ~FDI_PCDCLK; - I915_WRITE(_FDI_RXA_CTL, val); + I915_WRITE(FDI_RX_CTL(PIPE_A), val); - val = I915_READ(_FDI_RXA_CTL); + val = I915_READ(FDI_RX_CTL(PIPE_A)); val &= ~FDI_RX_PLL_ENABLE; - I915_WRITE(_FDI_RXA_CTL, val); + I915_WRITE(FDI_RX_CTL(PIPE_A), val); } void intel_ddi_get_config(struct intel_encoder *encoder, From 36c0d0cf33ed31fada15caac34d50555b33208bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 18 Sep 2015 20:03:31 +0300 Subject: [PATCH 062/134] drm/i915: s/_TRANSA_CHICKEN/TRANS_CHICKEN(PIPE_A)/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8e4fb80497a1..e7a3c1b4fc56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2050,9 +2050,9 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); /* Workaround: set timing override bit. */ - val = I915_READ(_TRANSA_CHICKEN2); + val = I915_READ(TRANS_CHICKEN2(PIPE_A)); val |= TRANS_CHICKEN2_TIMING_OVERRIDE; - I915_WRITE(_TRANSA_CHICKEN2, val); + I915_WRITE(TRANS_CHICKEN2(PIPE_A), val); val = TRANS_ENABLE; pipeconf_val = I915_READ(PIPECONF(cpu_transcoder)); @@ -2110,9 +2110,9 @@ static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) DRM_ERROR("Failed to disable PCH transcoder\n"); /* Workaround: clear timing override bit. */ - val = I915_READ(_TRANSA_CHICKEN2); + val = I915_READ(TRANS_CHICKEN2(PIPE_A)); val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE; - I915_WRITE(_TRANSA_CHICKEN2, val); + I915_WRITE(TRANS_CHICKEN2(PIPE_A), val); } /** diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9643a7c433d8..cb409c2f7860 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6640,8 +6640,8 @@ static void lpt_init_clock_gating(struct drm_device *dev) PCH_LP_PARTITION_LEVEL_DISABLE); /* WADPOClockGatingDisable:hsw */ - I915_WRITE(_TRANSA_CHICKEN1, - I915_READ(_TRANSA_CHICKEN1) | + I915_WRITE(TRANS_CHICKEN1(PIPE_A), + I915_READ(TRANS_CHICKEN1(PIPE_A)) | TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); } From 93f253187c2f565678bd7e5ca5f64c1043774f1b Mon Sep 17 00:00:00 2001 From: Alex Dai Date: Fri, 25 Sep 2015 11:46:56 -0700 Subject: [PATCH 063/134] drm/i915/guc: Media domain bit needed when notify GuC rc6 state GuC expects two bits for Render and Media domain separately when driver sends data via host2guc SAMPLE_FORCEWAKE. Bit 0 is for Render and bit 1 is for Media domain. v2: Keep sync with code for WaRsDoubleRc6WrlWithCoarsePowerGating v1: Add parameters definition to avoid magic value Signed-off-by: Alex Dai Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_guc_submission.c | 13 +++++++++++-- drivers/gpu/drm/i915/intel_guc_fwif.h | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 792d0b958a2c..0b1797f52aaf 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -155,12 +155,21 @@ static int host2guc_sample_forcewake(struct intel_guc *guc, struct i915_guc_client *client) { struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct drm_device *dev = dev_priv->dev; u32 data[2]; data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE; - data[1] = (intel_enable_rc6(dev_priv->dev)) ? 1 : 0; + /* WaRsDisableCoarsePowerGating:skl,bxt */ + if (!intel_enable_rc6(dev_priv->dev) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) || + (IS_SKL_GT3(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)) || + (IS_SKL_GT4(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0))) + data[1] = 0; + else + /* bit 0 and 1 are for Render and Media domain separately */ + data[1] = GUC_FORCEWAKE_RENDER | GUC_FORCEWAKE_MEDIA; - return host2guc_action(guc, data, 2); + return host2guc_action(guc, data, ARRAY_SIZE(data)); } /* diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index e1f47ba2b4b0..6c78fdf685e2 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -218,6 +218,9 @@ struct guc_context_desc { u64 desc_private; } __packed; +#define GUC_FORCEWAKE_RENDER (1 << 0) +#define GUC_FORCEWAKE_MEDIA (1 << 1) + /* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */ enum host2guc_action { HOST2GUC_ACTION_DEFAULT = 0x0, From d8135109e45d4cf352387b7de66c216a176e37f0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 29 Sep 2015 16:28:46 +0300 Subject: [PATCH 064/134] drm/i915/bxt: fix RC6 residency time calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RC6 residency time unit is 833.33ns on BXT according to the specification, so update the calculation accordingly. Use the same way as CHV/VLV to divide by the corresponding frequency, as I think this is the more natural unit for what the HW does internally. v2: - add missing IS_BROXTON check (Ville) Testcase: igt/pm_rc6_residency Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 74086eb5bf83..50ce9ce2b269 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -54,6 +54,9 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) units <<= 8; + } else if (IS_BROXTON(dev)) { + units = 1; + div = 1200; /* 833.33ns */ } raw_time = I915_READ(reg) * units; From 37d9078b9b395185947784ba8d71c0980e5aacad Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:06 -0700 Subject: [PATCH 065/134] drm/i915: Drop redundant watermark programming In commit commit e4ca061275ec6a48b66c6edebe08644e666994c0 Author: Patrik Jakobsson Date: Wed Jul 8 15:31:52 2015 +0200 drm/i915: Don't forget to mark crtc as inactive after disable we added extra watermark updates to all of the .crtc_disable() entrypoints to avoid problems problems with system resume on SKL. Those disable entrypoints are currently called in just two places in the driver: intel_atomic_commit (i.e., during a modeset) and intel_crtc_disable_noatomic (which is called during hardware readout). It seems that this extra watermark recalculation should only be important in the latter case (which happens during a resume operation); the former case should always have appropriate watermark programming happening at other points in the modeset sequence. Let's move the watermark update out of the .crtc_disable() entrypoints and place it directly in intel_crtc_disable_noatomic() so that it only happens on S3 resume and not during a regular modeset (since the existing watermark handling should properly update watermarks during normal atomic commits). Cc: Patrik Jakobsson Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e7a3c1b4fc56..f2df9b16d857 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5115,9 +5115,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_pll_disable(intel_crtc); } - - intel_crtc->active = false; - intel_update_watermarks(crtc); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5161,9 +5158,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); - - intel_crtc->active = false; - intel_update_watermarks(crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6254,9 +6248,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - - intel_crtc->active = false; - intel_update_watermarks(crtc); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) @@ -6276,6 +6267,8 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); + intel_crtc->active = false; + intel_update_watermarks(crtc); intel_disable_shared_dpll(intel_crtc); domains = intel_crtc->enabled_power_domains; From 43d59eda1f69631c267e06ab6b94ed3c14f1f6d1 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:07 -0700 Subject: [PATCH 066/134] drm/i915: Eliminate usage of plane_wm_parameters from ILK-style WM code (v2) Just pull the info out of the plane state structure rather than staging it in an additional structure. v2: Add 'visible' condition to sprites_scaled so that we don't limit the WM level when the sprite isn't enabled. (Ville) Signed-off-by: Matt Roper Reviewed-by(v1): Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 133 +++++++++++++++++--------------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cb409c2f7860..bffb6ebecff4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1777,9 +1777,6 @@ struct ilk_pipe_wm_parameters { bool active; uint32_t pipe_htotal; uint32_t pixel_rate; - struct intel_plane_wm_parameters pri; - struct intel_plane_wm_parameters spr; - struct intel_plane_wm_parameters cur; }; struct ilk_wm_maximums { @@ -1801,25 +1798,25 @@ struct intel_wm_config { * mem_value must be in 0.1us units. */ static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params, + const struct intel_plane_state *pstate, uint32_t mem_value, bool is_lp) { + int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; uint32_t method1, method2; - if (!params->active || !params->pri.enabled) + if (!params->active || !pstate->visible) return 0; - method1 = ilk_wm_method1(params->pixel_rate, - params->pri.bytes_per_pixel, - mem_value); + method1 = ilk_wm_method1(params->pixel_rate, bpp, mem_value); if (!is_lp) return method1; method2 = ilk_wm_method2(params->pixel_rate, params->pipe_htotal, - params->pri.horiz_pixels, - params->pri.bytes_per_pixel, + drm_rect_width(&pstate->dst), + bpp, mem_value); return min(method1, method2); @@ -1830,20 +1827,20 @@ static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params, * mem_value must be in 0.1us units. */ static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params, + const struct intel_plane_state *pstate, uint32_t mem_value) { + int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; uint32_t method1, method2; - if (!params->active || !params->spr.enabled) + if (!params->active || !pstate->visible) return 0; - method1 = ilk_wm_method1(params->pixel_rate, - params->spr.bytes_per_pixel, - mem_value); + method1 = ilk_wm_method1(params->pixel_rate, bpp, mem_value); method2 = ilk_wm_method2(params->pixel_rate, params->pipe_htotal, - params->spr.horiz_pixels, - params->spr.bytes_per_pixel, + drm_rect_width(&pstate->dst), + bpp, mem_value); return min(method1, method2); } @@ -1853,28 +1850,32 @@ static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params, * mem_value must be in 0.1us units. */ static uint32_t ilk_compute_cur_wm(const struct ilk_pipe_wm_parameters *params, + const struct intel_plane_state *pstate, uint32_t mem_value) { - if (!params->active || !params->cur.enabled) + int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; + + if (!params->active || !pstate->visible) return 0; return ilk_wm_method2(params->pixel_rate, params->pipe_htotal, - params->cur.horiz_pixels, - params->cur.bytes_per_pixel, + drm_rect_width(&pstate->dst), + bpp, mem_value); } /* Only for WM_LP. */ static uint32_t ilk_compute_fbc_wm(const struct ilk_pipe_wm_parameters *params, + const struct intel_plane_state *pstate, uint32_t pri_val) { - if (!params->active || !params->pri.enabled) + int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; + + if (!params->active || !pstate->visible) return 0; - return ilk_wm_fbc(pri_val, - params->pri.horiz_pixels, - params->pri.bytes_per_pixel); + return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), bpp); } static unsigned int ilk_display_fifo_size(const struct drm_device *dev) @@ -2039,10 +2040,12 @@ static bool ilk_validate_wm_level(int level, } static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, + const struct intel_crtc *intel_crtc, int level, const struct ilk_pipe_wm_parameters *p, struct intel_wm_level *result) { + struct intel_plane *intel_plane; uint16_t pri_latency = dev_priv->wm.pri_latency[level]; uint16_t spr_latency = dev_priv->wm.spr_latency[level]; uint16_t cur_latency = dev_priv->wm.cur_latency[level]; @@ -2054,10 +2057,29 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, cur_latency *= 5; } - result->pri_val = ilk_compute_pri_wm(p, pri_latency, level); - result->spr_val = ilk_compute_spr_wm(p, spr_latency); - result->cur_val = ilk_compute_cur_wm(p, cur_latency); - result->fbc_val = ilk_compute_fbc_wm(p, result->pri_val); + for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) { + struct intel_plane_state *pstate = + to_intel_plane_state(intel_plane->base.state); + + switch (intel_plane->base.type) { + case DRM_PLANE_TYPE_PRIMARY: + result->pri_val = ilk_compute_pri_wm(p, pstate, + pri_latency, + level); + result->fbc_val = ilk_compute_fbc_wm(p, pstate, + result->pri_val); + break; + case DRM_PLANE_TYPE_OVERLAY: + result->spr_val = ilk_compute_spr_wm(p, pstate, + spr_latency); + break; + case DRM_PLANE_TYPE_CURSOR: + result->cur_val = ilk_compute_cur_wm(p, pstate, + cur_latency); + break; + } + } + result->enable = true; } @@ -2319,10 +2341,7 @@ static void skl_setup_wm_latency(struct drm_device *dev) static void ilk_compute_wm_parameters(struct drm_crtc *crtc, struct ilk_pipe_wm_parameters *p) { - struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - struct drm_plane *plane; if (!intel_crtc->active) return; @@ -2330,32 +2349,6 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, p->active = true; p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; p->pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); - - if (crtc->primary->state->fb) - p->pri.bytes_per_pixel = - crtc->primary->state->fb->bits_per_pixel / 8; - else - p->pri.bytes_per_pixel = 4; - - p->cur.bytes_per_pixel = 4; - /* - * TODO: for now, assume primary and cursor planes are always enabled. - * Setting them to false makes the screen flicker. - */ - p->pri.enabled = true; - p->cur.enabled = true; - - p->pri.horiz_pixels = intel_crtc->config->pipe_src_w; - p->cur.horiz_pixels = intel_crtc->base.cursor->state->crtc_w; - - drm_for_each_legacy_plane(plane, dev) { - struct intel_plane *intel_plane = to_intel_plane(plane); - - if (intel_plane->pipe == pipe) { - p->spr = intel_plane->wm; - break; - } - } } static void ilk_compute_wm_config(struct drm_device *dev, @@ -2383,28 +2376,42 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; const struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane; + struct intel_plane_state *sprstate = NULL; int level, max_level = ilk_wm_max_level(dev); /* LP0 watermark maximums depend on this pipe alone */ struct intel_wm_config config = { .num_pipes_active = 1, - .sprites_enabled = params->spr.enabled, - .sprites_scaled = params->spr.scaled, }; struct ilk_wm_maximums max; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) { + sprstate = to_intel_plane_state(intel_plane->base.state); + break; + } + } + + config.sprites_enabled = sprstate->visible; + config.sprites_scaled = sprstate->visible && + (drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 || + drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16); + + pipe_wm->pipe_enabled = params->active; - pipe_wm->sprites_enabled = params->spr.enabled; - pipe_wm->sprites_scaled = params->spr.scaled; + pipe_wm->sprites_enabled = sprstate->visible; + pipe_wm->sprites_scaled = config.sprites_scaled; /* ILK/SNB: LP2+ watermarks only w/o sprites */ - if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled) + if (INTEL_INFO(dev)->gen <= 6 && sprstate->visible) max_level = 1; /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */ - if (params->spr.scaled) + if (config.sprites_scaled) max_level = 0; - ilk_compute_wm_level(dev_priv, 0, params, &pipe_wm->wm[0]); + ilk_compute_wm_level(dev_priv, intel_crtc, 0, params, &pipe_wm->wm[0]); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); @@ -2421,7 +2428,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, for (level = 1; level <= max_level; level++) { struct intel_wm_level wm = {}; - ilk_compute_wm_level(dev_priv, level, params, &wm); + ilk_compute_wm_level(dev_priv, intel_crtc, level, params, &wm); /* * Disable any watermark level that exceeds the From 7221fc333dbe1743a3dff155b03527fda90d4ec1 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:08 -0700 Subject: [PATCH 067/134] drm/i915: Eliminate usage of pipe_wm_parameters from ILK-style WM (v2) Just pull the info out of the CRTC state structure rather than staging it in an additional structure. Note that we use cstate->active rather than intel_crtc->active which may appear to be a change in behavior. However since we're no longer trying to recalculate watermarks during the "pipe off" stage of a modeset, intel_crtc->active and cstate->active should always be identical when watermarks are calculated (at least for ILK-style platforms). v2: Clarify reasoning for cstate->active and add a WARN_ON to the code to assert that it really is always identical to intel_crtc->active as expected. Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 84 ++++++++++++--------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bffb6ebecff4..a9615ba20319 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1773,12 +1773,6 @@ struct skl_pipe_wm_parameters { struct intel_plane_wm_parameters cursor; }; -struct ilk_pipe_wm_parameters { - bool active; - uint32_t pipe_htotal; - uint32_t pixel_rate; -}; - struct ilk_wm_maximums { uint16_t pri; uint16_t spr; @@ -1797,7 +1791,7 @@ struct intel_wm_config { * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. */ -static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params, +static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t mem_value, bool is_lp) @@ -1805,16 +1799,16 @@ static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params, int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; uint32_t method1, method2; - if (!params->active || !pstate->visible) + if (!cstate->base.active || !pstate->visible) return 0; - method1 = ilk_wm_method1(params->pixel_rate, bpp, mem_value); + method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), bpp, mem_value); if (!is_lp) return method1; - method2 = ilk_wm_method2(params->pixel_rate, - params->pipe_htotal, + method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate), + cstate->base.adjusted_mode.crtc_htotal, drm_rect_width(&pstate->dst), bpp, mem_value); @@ -1826,19 +1820,19 @@ static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params, * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. */ -static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params, +static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t mem_value) { int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; uint32_t method1, method2; - if (!params->active || !pstate->visible) + if (!cstate->base.active || !pstate->visible) return 0; - method1 = ilk_wm_method1(params->pixel_rate, bpp, mem_value); - method2 = ilk_wm_method2(params->pixel_rate, - params->pipe_htotal, + method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), bpp, mem_value); + method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate), + cstate->base.adjusted_mode.crtc_htotal, drm_rect_width(&pstate->dst), bpp, mem_value); @@ -1849,30 +1843,30 @@ static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params, * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. */ -static uint32_t ilk_compute_cur_wm(const struct ilk_pipe_wm_parameters *params, +static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t mem_value) { int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; - if (!params->active || !pstate->visible) + if (!cstate->base.active || !pstate->visible) return 0; - return ilk_wm_method2(params->pixel_rate, - params->pipe_htotal, + return ilk_wm_method2(ilk_pipe_pixel_rate(cstate), + cstate->base.adjusted_mode.crtc_htotal, drm_rect_width(&pstate->dst), bpp, mem_value); } /* Only for WM_LP. */ -static uint32_t ilk_compute_fbc_wm(const struct ilk_pipe_wm_parameters *params, +static uint32_t ilk_compute_fbc_wm(const struct intel_crtc_state *cstate, const struct intel_plane_state *pstate, uint32_t pri_val) { int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0; - if (!params->active || !pstate->visible) + if (!cstate->base.active || !pstate->visible) return 0; return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), bpp); @@ -2042,7 +2036,7 @@ static bool ilk_validate_wm_level(int level, static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, const struct intel_crtc *intel_crtc, int level, - const struct ilk_pipe_wm_parameters *p, + struct intel_crtc_state *cstate, struct intel_wm_level *result) { struct intel_plane *intel_plane; @@ -2063,18 +2057,18 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, switch (intel_plane->base.type) { case DRM_PLANE_TYPE_PRIMARY: - result->pri_val = ilk_compute_pri_wm(p, pstate, + result->pri_val = ilk_compute_pri_wm(cstate, pstate, pri_latency, level); - result->fbc_val = ilk_compute_fbc_wm(p, pstate, + result->fbc_val = ilk_compute_fbc_wm(cstate, pstate, result->pri_val); break; case DRM_PLANE_TYPE_OVERLAY: - result->spr_val = ilk_compute_spr_wm(p, pstate, + result->spr_val = ilk_compute_spr_wm(cstate, pstate, spr_latency); break; case DRM_PLANE_TYPE_CURSOR: - result->cur_val = ilk_compute_cur_wm(p, pstate, + result->cur_val = ilk_compute_cur_wm(cstate, pstate, cur_latency); break; } @@ -2338,19 +2332,6 @@ static void skl_setup_wm_latency(struct drm_device *dev) intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency); } -static void ilk_compute_wm_parameters(struct drm_crtc *crtc, - struct ilk_pipe_wm_parameters *p) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - if (!intel_crtc->active) - return; - - p->active = true; - p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; - p->pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); -} - static void ilk_compute_wm_config(struct drm_device *dev, struct intel_wm_config *config) { @@ -2370,10 +2351,10 @@ static void ilk_compute_wm_config(struct drm_device *dev, } /* Compute new watermarks for the pipe */ -static bool intel_compute_pipe_wm(struct drm_crtc *crtc, - const struct ilk_pipe_wm_parameters *params, +static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, struct intel_pipe_wm *pipe_wm) { + struct drm_crtc *crtc = cstate->base.crtc; struct drm_device *dev = crtc->dev; const struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -2398,8 +2379,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, (drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 || drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16); - - pipe_wm->pipe_enabled = params->active; + pipe_wm->pipe_enabled = cstate->base.active; pipe_wm->sprites_enabled = sprstate->visible; pipe_wm->sprites_scaled = config.sprites_scaled; @@ -2411,7 +2391,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, if (config.sprites_scaled) max_level = 0; - ilk_compute_wm_level(dev_priv, intel_crtc, 0, params, &pipe_wm->wm[0]); + ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); @@ -2428,7 +2408,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc, for (level = 1; level <= max_level; level++) { struct intel_wm_level wm = {}; - ilk_compute_wm_level(dev_priv, intel_crtc, level, params, &wm); + ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm); /* * Disable any watermark level that exceeds the @@ -3759,19 +3739,19 @@ skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc, static void ilk_update_wm(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct ilk_wm_maximums max; - struct ilk_pipe_wm_parameters params = {}; struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; struct intel_pipe_wm pipe_wm = {}; struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct intel_wm_config config = {}; - ilk_compute_wm_parameters(crtc, ¶ms); + WARN_ON(cstate->base.active != intel_crtc->active); - intel_compute_pipe_wm(crtc, ¶ms, &pipe_wm); + intel_compute_pipe_wm(cstate, &pipe_wm); if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) return; @@ -3811,12 +3791,6 @@ ilk_update_sprite_wm(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); - intel_plane->wm.enabled = enabled; - intel_plane->wm.scaled = scaled; - intel_plane->wm.horiz_pixels = sprite_width; - intel_plane->wm.vert_pixels = sprite_width; - intel_plane->wm.bytes_per_pixel = pixel_size; - /* * IVB workaround: must disable low power watermarks for at least * one frame before enabling scaling. LP watermarks can be re-enabled From 31409e97ef708ba52ddcb9a7b65b8b878ecc08f3 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:09 -0700 Subject: [PATCH 068/134] drm/i915: Determine I915_MAX_PLANES from plane enum Let the compiler figure out what I915_MAX_PLANES is from 'enum plane' so that we don't need a separate #define. While we're at it, add the cursor plane to the enum. This will cause I915_MAX_PLANES to now include the cursor plane in its count (it didn't previously). This change is safe since we currently only use this value in array declarations (never in the actual code logic); we just wind up allocating slightly more memory than we need to. A followup patch will cause various parts of the code to start using the extra array element where appropriate. (This patch probably should have been squashed with the followup patch, but I couldn't figure out how to get Coccinelle to modify enum declarations...) Suggested-by: Ander Conselvan De Oliveira Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ee478acc0a5b..497ab4e7fc00 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -131,17 +131,17 @@ enum transcoder { #define transcoder_name(t) ((t) + 'A') /* - * This is the maximum (across all platforms) number of planes (primary + - * sprites) that can be active at the same time on one pipe. - * - * This value doesn't count the cursor plane. + * 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, + * which means some arrays of size I915_MAX_PLANES may have unused entries + * between the topmost sprite plane and the cursor plane. */ -#define I915_MAX_PLANES 4 - enum plane { PLANE_A = 0, PLANE_B, PLANE_C, + PLANE_CURSOR, + I915_MAX_PLANES, }; #define plane_name(p) ((p) + 'A') From 4969d33ed91d51262691e0479faad16f57688146 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:10 -0700 Subject: [PATCH 069/134] drm/i915/skl: Simplify wm structures slightly (v2) A bunch of SKL watermark-related structures have the cursor plane as a separate entry from the rest of the planes. Since a previous patch updated I915_MAX_PLANES such that those plane arrays now have a slot for the cursor, update the code to use the new slot in the existing plane arrays and kill off the cursor-specific structures. There shouldn't be any functional change here; this is just shuffling around how the data is stored in some of the data structures. The whole patch is generated with Coccinelle via the following semantic patch: @@ struct skl_pipe_wm_parameters WMP; @@ - WMP.cursor + WMP.plane[PLANE_CURSOR] @@ struct skl_pipe_wm_parameters *WMP; @@ - WMP->cursor + WMP->plane[PLANE_CURSOR] @@ @@ struct skl_pipe_wm_parameters { ... - struct intel_plane_wm_parameters cursor; ... }; @@ struct skl_ddb_allocation DDB; expression E; @@ - DDB.cursor[E] + DDB.plane[E][PLANE_CURSOR] @@ struct skl_ddb_allocation *DDB; expression E; @@ - DDB->cursor[E] + DDB->plane[E][PLANE_CURSOR] @@ @@ struct skl_ddb_allocation { ... - struct skl_ddb_entry cursor[I915_MAX_PIPES]; ... }; @@ struct skl_wm_values WMV; expression E1, E2; @@ ( - WMV.cursor[E1][E2] + WMV.plane[E1][PLANE_CURSOR][E2] | - WMV.cursor_trans[E1] + WMV.plane_trans[E1][PLANE_CURSOR] ) @@ struct skl_wm_values *WMV; expression E1, E2; @@ ( - WMV->cursor[E1][E2] + WMV->plane[E1][PLANE_CURSOR][E2] | - WMV->cursor_trans[E1] + WMV->plane_trans[E1][PLANE_CURSOR] ) @@ @@ struct skl_wm_values { ... - uint32_t cursor[I915_MAX_PIPES][8]; ... - uint32_t cursor_trans[I915_MAX_PIPES]; ... }; @@ struct skl_wm_level WML; @@ ( - WML.cursor_en + WML.plane_en[PLANE_CURSOR] | - WML.cursor_res_b + WML.plane_res_b[PLANE_CURSOR] | - WML.cursor_res_l + WML.plane_res_l[PLANE_CURSOR] ) @@ struct skl_wm_level *WML; @@ ( - WML->cursor_en + WML->plane_en[PLANE_CURSOR] | - WML->cursor_res_b + WML->plane_res_b[PLANE_CURSOR] | - WML->cursor_res_l + WML->plane_res_l[PLANE_CURSOR] ) @@ @@ struct skl_wm_level { ... - bool cursor_en; ... - uint16_t cursor_res_b; - uint8_t cursor_res_l; ... }; v2: Use a PLANE_CURSOR enum entry rather than making the code reference I915_MAX_PLANES or I915_MAX_PLANES+1, which was confusing. (Ander) Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 8 +-- drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_pm.c | 93 ++++++++++++++-------------- 4 files changed, 52 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2ac1ba813593..77ee8c5062b9 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3155,7 +3155,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused) skl_ddb_entry_size(entry)); } - entry = &ddb->cursor[pipe]; + entry = &ddb->plane[pipe][PLANE_CURSOR]; seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start, entry->end, skl_ddb_entry_size(entry)); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 497ab4e7fc00..29ce11fc2408 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1578,8 +1578,7 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1, struct skl_ddb_allocation { struct skl_ddb_entry pipe[I915_MAX_PIPES]; struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; /* packed/uv */ - struct skl_ddb_entry y_plane[I915_MAX_PIPES][I915_MAX_PLANES]; /* y-plane */ - struct skl_ddb_entry cursor[I915_MAX_PIPES]; + struct skl_ddb_entry y_plane[I915_MAX_PIPES][I915_MAX_PLANES]; }; struct skl_wm_values { @@ -1587,18 +1586,13 @@ struct skl_wm_values { struct skl_ddb_allocation ddb; uint32_t wm_linetime[I915_MAX_PIPES]; uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8]; - uint32_t cursor[I915_MAX_PIPES][8]; uint32_t plane_trans[I915_MAX_PIPES][I915_MAX_PLANES]; - uint32_t cursor_trans[I915_MAX_PIPES]; }; struct skl_wm_level { bool plane_en[I915_MAX_PLANES]; - bool cursor_en; uint16_t plane_res_b[I915_MAX_PLANES]; uint8_t plane_res_l[I915_MAX_PLANES]; - uint16_t cursor_res_b; - uint8_t cursor_res_l; }; /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f2df9b16d857..305abaa0d000 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12587,8 +12587,8 @@ static void check_wm_state(struct drm_device *dev) } /* cursor */ - hw_entry = &hw_ddb.cursor[pipe]; - sw_entry = &sw_ddb->cursor[pipe]; + hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR]; + sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR]; if (skl_ddb_entry_equal(hw_entry, sw_entry)) continue; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a9615ba20319..0004362f6c5e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1770,7 +1770,6 @@ struct skl_pipe_wm_parameters { uint32_t pipe_htotal; uint32_t pixel_rate; /* in KHz */ struct intel_plane_wm_parameters plane[I915_MAX_PLANES]; - struct intel_plane_wm_parameters cursor; }; struct ilk_wm_maximums { @@ -2884,7 +2883,8 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, } val = I915_READ(CUR_BUF_CFG(pipe)); - skl_ddb_entry_init_from_hw(&ddb->cursor[pipe], val); + skl_ddb_entry_init_from_hw(&ddb->plane[pipe][PLANE_CURSOR], + val); } } @@ -2953,13 +2953,14 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, alloc_size = skl_ddb_entry_size(alloc); if (alloc_size == 0) { memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); - memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe])); + memset(&ddb->plane[pipe][PLANE_CURSOR], 0, + sizeof(ddb->plane[pipe][PLANE_CURSOR])); return; } cursor_blocks = skl_cursor_allocation(config); - ddb->cursor[pipe].start = alloc->end - cursor_blocks; - ddb->cursor[pipe].end = alloc->end; + ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - cursor_blocks; + ddb->plane[pipe][PLANE_CURSOR].end = alloc->end; alloc_size -= cursor_blocks; alloc->end -= cursor_blocks; @@ -3098,8 +3099,8 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb, sizeof(new_ddb->plane[pipe]))) return true; - if (memcmp(&new_ddb->cursor[pipe], &cur_ddb->cursor[pipe], - sizeof(new_ddb->cursor[pipe]))) + if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR], + sizeof(new_ddb->plane[pipe][PLANE_CURSOR]))) return true; return false; @@ -3159,17 +3160,17 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, p->plane[0].rotation = crtc->primary->state->rotation; fb = crtc->cursor->state->fb; - p->cursor.y_bytes_per_pixel = 0; + p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0; if (fb) { - p->cursor.enabled = true; - p->cursor.bytes_per_pixel = fb->bits_per_pixel / 8; - p->cursor.horiz_pixels = crtc->cursor->state->crtc_w; - p->cursor.vert_pixels = crtc->cursor->state->crtc_h; + p->plane[PLANE_CURSOR].enabled = true; + p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8; + p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w; + p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h; } else { - p->cursor.enabled = false; - p->cursor.bytes_per_pixel = 0; - p->cursor.horiz_pixels = 64; - p->cursor.vert_pixels = 64; + p->plane[PLANE_CURSOR].enabled = false; + p->plane[PLANE_CURSOR].bytes_per_pixel = 0; + p->plane[PLANE_CURSOR].horiz_pixels = 64; + p->plane[PLANE_CURSOR].vert_pixels = 64; } } @@ -3283,11 +3284,12 @@ static void skl_compute_wm_level(const struct drm_i915_private *dev_priv, &result->plane_res_l[i]); } - ddb_blocks = skl_ddb_entry_size(&ddb->cursor[pipe]); - result->cursor_en = skl_compute_plane_wm(dev_priv, p, &p->cursor, + ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]); + result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p, + &p->plane[PLANE_CURSOR], ddb_blocks, level, - &result->cursor_res_b, - &result->cursor_res_l); + &result->plane_res_b[PLANE_CURSOR], + &result->plane_res_l[PLANE_CURSOR]); } static uint32_t @@ -3315,7 +3317,7 @@ static void skl_compute_transition_wm(struct drm_crtc *crtc, /* Until we know more, just disable transition WMs */ for (i = 0; i < intel_num_planes(intel_crtc); i++) trans_wm->plane_en[i] = false; - trans_wm->cursor_en = false; + trans_wm->plane_en[PLANE_CURSOR] = false; } static void skl_compute_pipe_wm(struct drm_crtc *crtc, @@ -3364,13 +3366,13 @@ static void skl_compute_wm_results(struct drm_device *dev, temp = 0; - temp |= p_wm->wm[level].cursor_res_l << PLANE_WM_LINES_SHIFT; - temp |= p_wm->wm[level].cursor_res_b; + temp |= p_wm->wm[level].plane_res_l[PLANE_CURSOR] << PLANE_WM_LINES_SHIFT; + temp |= p_wm->wm[level].plane_res_b[PLANE_CURSOR]; - if (p_wm->wm[level].cursor_en) + if (p_wm->wm[level].plane_en[PLANE_CURSOR]) temp |= PLANE_WM_EN; - r->cursor[pipe][level] = temp; + r->plane[pipe][PLANE_CURSOR][level] = temp; } @@ -3386,12 +3388,12 @@ static void skl_compute_wm_results(struct drm_device *dev, } temp = 0; - temp |= p_wm->trans_wm.cursor_res_l << PLANE_WM_LINES_SHIFT; - temp |= p_wm->trans_wm.cursor_res_b; - if (p_wm->trans_wm.cursor_en) + temp |= p_wm->trans_wm.plane_res_l[PLANE_CURSOR] << PLANE_WM_LINES_SHIFT; + temp |= p_wm->trans_wm.plane_res_b[PLANE_CURSOR]; + if (p_wm->trans_wm.plane_en[PLANE_CURSOR]) temp |= PLANE_WM_EN; - r->cursor_trans[pipe] = temp; + r->plane_trans[pipe][PLANE_CURSOR] = temp; r->wm_linetime[pipe] = p_wm->linetime; } @@ -3425,12 +3427,13 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(PLANE_WM(pipe, i, level), new->plane[pipe][i][level]); I915_WRITE(CUR_WM(pipe, level), - new->cursor[pipe][level]); + new->plane[pipe][PLANE_CURSOR][level]); } for (i = 0; i < intel_num_planes(crtc); i++) I915_WRITE(PLANE_WM_TRANS(pipe, i), new->plane_trans[pipe][i]); - I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]); + I915_WRITE(CUR_WM_TRANS(pipe), + new->plane_trans[pipe][PLANE_CURSOR]); for (i = 0; i < intel_num_planes(crtc); i++) { skl_ddb_entry_write(dev_priv, @@ -3442,7 +3445,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv, } skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), - &new->ddb.cursor[pipe]); + &new->ddb.plane[pipe][PLANE_CURSOR]); } } @@ -3655,10 +3658,9 @@ static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe) watermarks->wm_linetime[pipe] = 0; memset(watermarks->plane[pipe], 0, sizeof(uint32_t) * 8 * I915_MAX_PLANES); - memset(watermarks->cursor[pipe], 0, sizeof(uint32_t) * 8); memset(watermarks->plane_trans[pipe], 0, sizeof(uint32_t) * I915_MAX_PLANES); - watermarks->cursor_trans[pipe] = 0; + watermarks->plane_trans[pipe][PLANE_CURSOR] = 0; /* Clear ddb entries for pipe */ memset(&watermarks->ddb.pipe[pipe], 0, sizeof(struct skl_ddb_entry)); @@ -3666,7 +3668,8 @@ static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe) sizeof(struct skl_ddb_entry) * I915_MAX_PLANES); memset(&watermarks->ddb.y_plane[pipe], 0, sizeof(struct skl_ddb_entry) * I915_MAX_PLANES); - memset(&watermarks->ddb.cursor[pipe], 0, sizeof(struct skl_ddb_entry)); + memset(&watermarks->ddb.plane[pipe][PLANE_CURSOR], 0, + sizeof(struct skl_ddb_entry)); } @@ -3822,10 +3825,10 @@ static void skl_pipe_wm_active_state(uint32_t val, (val >> PLANE_WM_LINES_SHIFT) & PLANE_WM_LINES_MASK; } else { - active->wm[level].cursor_en = is_enabled; - active->wm[level].cursor_res_b = + active->wm[level].plane_en[PLANE_CURSOR] = is_enabled; + active->wm[level].plane_res_b[PLANE_CURSOR] = val & PLANE_WM_BLOCKS_MASK; - active->wm[level].cursor_res_l = + active->wm[level].plane_res_l[PLANE_CURSOR] = (val >> PLANE_WM_LINES_SHIFT) & PLANE_WM_LINES_MASK; } @@ -3838,10 +3841,10 @@ static void skl_pipe_wm_active_state(uint32_t val, (val >> PLANE_WM_LINES_SHIFT) & PLANE_WM_LINES_MASK; } else { - active->trans_wm.cursor_en = is_enabled; - active->trans_wm.cursor_res_b = + active->trans_wm.plane_en[PLANE_CURSOR] = is_enabled; + active->trans_wm.plane_res_b[PLANE_CURSOR] = val & PLANE_WM_BLOCKS_MASK; - active->trans_wm.cursor_res_l = + active->trans_wm.plane_res_l[PLANE_CURSOR] = (val >> PLANE_WM_LINES_SHIFT) & PLANE_WM_LINES_MASK; } @@ -3867,12 +3870,12 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) for (i = 0; i < intel_num_planes(intel_crtc); i++) hw->plane[pipe][i][level] = I915_READ(PLANE_WM(pipe, i, level)); - hw->cursor[pipe][level] = I915_READ(CUR_WM(pipe, level)); + hw->plane[pipe][PLANE_CURSOR][level] = I915_READ(CUR_WM(pipe, level)); } for (i = 0; i < intel_num_planes(intel_crtc); i++) hw->plane_trans[pipe][i] = I915_READ(PLANE_WM_TRANS(pipe, i)); - hw->cursor_trans[pipe] = I915_READ(CUR_WM_TRANS(pipe)); + hw->plane_trans[pipe][PLANE_CURSOR] = I915_READ(CUR_WM_TRANS(pipe)); if (!intel_crtc->active) return; @@ -3887,7 +3890,7 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) skl_pipe_wm_active_state(temp, active, false, false, i, level); } - temp = hw->cursor[pipe][level]; + temp = hw->plane[pipe][PLANE_CURSOR][level]; skl_pipe_wm_active_state(temp, active, false, true, i, level); } @@ -3896,7 +3899,7 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) skl_pipe_wm_active_state(temp, active, true, false, i, 0); } - temp = hw->cursor_trans[pipe]; + temp = hw->plane_trans[pipe][PLANE_CURSOR]; skl_pipe_wm_active_state(temp, active, true, true, i, 0); } From 3a05f5e2e78eab7ffe816abb59b6769e331a1957 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:11 -0700 Subject: [PATCH 070/134] drm/i915/skl: Eliminate usage of pipe_wm_parameters from SKL-style WM (v3) Just pull the info out of the state structures rather than staging it in an additional set of structures. To make this more straightforward, we change the signature of several internal WM functions to take the crtc state as a parameter. v2: - Don't forget to skip cursor planes on a loop in the DDB allocation function to match original behavior. (Ander) - Change a use of intel_crtc->active to cstate->active. They should be identical, but it's better to be consistent. (Ander) - Rework more function signatures to pass states rather than crtc for consistency. (Ander) v3: - Add missing "+ 1" to skl_wm_plane_id()'s 'overlay' case. (Maarten) - Packed formats should pass '0' to drm_format_plane_cpp(), not 1. (Maarten) - Drop unwanted WARN_ON() for disabled planes when calculating data rate for SKL. (Maarten) Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 326 +++++++++++++++----------------- 1 file changed, 151 insertions(+), 175 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0004362f6c5e..3aca66d99353 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1765,13 +1765,6 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; } -struct skl_pipe_wm_parameters { - bool active; - uint32_t pipe_htotal; - uint32_t pixel_rate; /* in KHz */ - struct intel_plane_wm_parameters plane[I915_MAX_PLANES]; -}; - struct ilk_wm_maximums { uint16_t pri; uint16_t spr; @@ -2812,18 +2805,40 @@ static bool ilk_disable_lp_wm(struct drm_device *dev) #define SKL_DDB_SIZE 896 /* in blocks */ #define BXT_DDB_SIZE 512 +/* + * Return the index of a plane in the SKL DDB and wm result arrays. Primary + * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and + * other universal planes are in indices 1..n. Note that this may leave unused + * indices between the top "sprite" plane and the cursor. + */ +static int +skl_wm_plane_id(const struct intel_plane *plane) +{ + switch (plane->base.type) { + case DRM_PLANE_TYPE_PRIMARY: + return 0; + case DRM_PLANE_TYPE_CURSOR: + return PLANE_CURSOR; + case DRM_PLANE_TYPE_OVERLAY: + return plane->plane + 1; + default: + MISSING_CASE(plane->base.type); + return plane->plane; + } +} + static void skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, - struct drm_crtc *for_crtc, + const struct intel_crtc_state *cstate, const struct intel_wm_config *config, - const struct skl_pipe_wm_parameters *params, struct skl_ddb_entry *alloc /* out */) { + struct drm_crtc *for_crtc = cstate->base.crtc; struct drm_crtc *crtc; unsigned int pipe_size, ddb_size; int nth_active_pipe; - if (!params->active) { + if (!cstate->base.active) { alloc->start = 0; alloc->end = 0; return; @@ -2889,19 +2904,29 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, } static unsigned int -skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y) +skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, + const struct drm_plane_state *pstate, + int y) { + struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); + struct drm_framebuffer *fb = pstate->fb; /* for planar format */ - if (p->y_bytes_per_pixel) { + if (fb->pixel_format == DRM_FORMAT_NV12) { if (y) /* y-plane data rate */ - return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel; + return intel_crtc->config->pipe_src_w * + intel_crtc->config->pipe_src_h * + drm_format_plane_cpp(fb->pixel_format, 0); else /* uv-plane data rate */ - return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel; + return (intel_crtc->config->pipe_src_w/2) * + (intel_crtc->config->pipe_src_h/2) * + drm_format_plane_cpp(fb->pixel_format, 1); } /* for packed formats */ - return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel; + return intel_crtc->config->pipe_src_w * + intel_crtc->config->pipe_src_h * + drm_format_plane_cpp(fb->pixel_format, 0); } /* @@ -2910,46 +2935,51 @@ skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y) * 3 * 4096 * 8192 * 4 < 2^32 */ static unsigned int -skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc, - const struct skl_pipe_wm_parameters *params) +skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate) { + struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); + struct drm_device *dev = intel_crtc->base.dev; + const struct intel_plane *intel_plane; unsigned int total_data_rate = 0; - int plane; - for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { - const struct intel_plane_wm_parameters *p; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + const struct drm_plane_state *pstate = intel_plane->base.state; - p = ¶ms->plane[plane]; - if (!p->enabled) + if (pstate->fb == NULL) continue; - total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */ - if (p->y_bytes_per_pixel) { - total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */ - } + /* packed/uv */ + total_data_rate += skl_plane_relative_data_rate(cstate, + pstate, + 0); + + if (pstate->fb->pixel_format == DRM_FORMAT_NV12) + /* y-plane */ + total_data_rate += skl_plane_relative_data_rate(cstate, + pstate, + 1); } return total_data_rate; } static void -skl_allocate_pipe_ddb(struct drm_crtc *crtc, +skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, const struct intel_wm_config *config, - const struct skl_pipe_wm_parameters *params, struct skl_ddb_allocation *ddb /* out */) { + struct drm_crtc *crtc = cstate->base.crtc; struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane; enum pipe pipe = intel_crtc->pipe; struct skl_ddb_entry *alloc = &ddb->pipe[pipe]; uint16_t alloc_size, start, cursor_blocks; uint16_t minimum[I915_MAX_PLANES]; uint16_t y_minimum[I915_MAX_PLANES]; unsigned int total_data_rate; - int plane; - skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc); + skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc); alloc_size = skl_ddb_entry_size(alloc); if (alloc_size == 0) { memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); @@ -2966,17 +2996,20 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, alloc->end -= cursor_blocks; /* 1. Allocate the mininum required blocks for each active plane */ - for_each_plane(dev_priv, pipe, plane) { - const struct intel_plane_wm_parameters *p; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + struct drm_plane *plane = &intel_plane->base; + struct drm_framebuffer *fb = plane->fb; + int id = skl_wm_plane_id(intel_plane); - p = ¶ms->plane[plane]; - if (!p->enabled) + if (fb == NULL) + continue; + if (plane->type == DRM_PLANE_TYPE_CURSOR) continue; - minimum[plane] = 8; - alloc_size -= minimum[plane]; - y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0; - alloc_size -= y_minimum[plane]; + minimum[id] = 8; + alloc_size -= minimum[id]; + y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0; + alloc_size -= y_minimum[id]; } /* @@ -2985,45 +3018,50 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, * * FIXME: we may not allocate every single block here. */ - total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params); + total_data_rate = skl_get_total_relative_data_rate(cstate); start = alloc->start; - for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { - const struct intel_plane_wm_parameters *p; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + struct drm_plane *plane = &intel_plane->base; + struct drm_plane_state *pstate = intel_plane->base.state; unsigned int data_rate, y_data_rate; uint16_t plane_blocks, y_plane_blocks = 0; + int id = skl_wm_plane_id(intel_plane); - p = ¶ms->plane[plane]; - if (!p->enabled) + if (pstate->fb == NULL) + continue; + if (plane->type == DRM_PLANE_TYPE_CURSOR) continue; - data_rate = skl_plane_relative_data_rate(p, 0); + data_rate = skl_plane_relative_data_rate(cstate, pstate, 0); /* * allocation for (packed formats) or (uv-plane part of planar format): * promote the expression to 64 bits to avoid overflowing, the * result is < available as data_rate / total_data_rate < 1 */ - plane_blocks = minimum[plane]; + plane_blocks = minimum[id]; plane_blocks += div_u64((uint64_t)alloc_size * data_rate, total_data_rate); - ddb->plane[pipe][plane].start = start; - ddb->plane[pipe][plane].end = start + plane_blocks; + ddb->plane[pipe][id].start = start; + ddb->plane[pipe][id].end = start + plane_blocks; start += plane_blocks; /* * allocation for y_plane part of planar format: */ - if (p->y_bytes_per_pixel) { - y_data_rate = skl_plane_relative_data_rate(p, 1); - y_plane_blocks = y_minimum[plane]; + if (pstate->fb->pixel_format == DRM_FORMAT_NV12) { + y_data_rate = skl_plane_relative_data_rate(cstate, + pstate, + 1); + y_plane_blocks = y_minimum[id]; y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate, total_data_rate); - ddb->y_plane[pipe][plane].start = start; - ddb->y_plane[pipe][plane].end = start + y_plane_blocks; + ddb->y_plane[pipe][id].start = start; + ddb->y_plane[pipe][id].end = start + y_plane_blocks; start += y_plane_blocks; } @@ -3124,73 +3162,16 @@ static void skl_compute_wm_global_parameters(struct drm_device *dev, } } -static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *p) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - struct drm_plane *plane; - struct drm_framebuffer *fb; - int i = 1; /* Index for sprite planes start */ - - p->active = intel_crtc->active; - if (p->active) { - p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; - p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config); - - fb = crtc->primary->state->fb; - /* For planar: Bpp is for uv plane, y_Bpp is for y plane */ - if (fb) { - p->plane[0].enabled = true; - p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ? - drm_format_plane_cpp(fb->pixel_format, 1) : - drm_format_plane_cpp(fb->pixel_format, 0); - p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ? - drm_format_plane_cpp(fb->pixel_format, 0) : 0; - p->plane[0].tiling = fb->modifier[0]; - } else { - p->plane[0].enabled = false; - p->plane[0].bytes_per_pixel = 0; - p->plane[0].y_bytes_per_pixel = 0; - p->plane[0].tiling = DRM_FORMAT_MOD_NONE; - } - p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w; - p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h; - p->plane[0].rotation = crtc->primary->state->rotation; - - fb = crtc->cursor->state->fb; - p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0; - if (fb) { - p->plane[PLANE_CURSOR].enabled = true; - p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8; - p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w; - p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h; - } else { - p->plane[PLANE_CURSOR].enabled = false; - p->plane[PLANE_CURSOR].bytes_per_pixel = 0; - p->plane[PLANE_CURSOR].horiz_pixels = 64; - p->plane[PLANE_CURSOR].vert_pixels = 64; - } - } - - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - struct intel_plane *intel_plane = to_intel_plane(plane); - - if (intel_plane->pipe == pipe && - plane->type == DRM_PLANE_TYPE_OVERLAY) - p->plane[i++] = intel_plane->wm; - } -} - static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, - struct skl_pipe_wm_parameters *p, - struct intel_plane_wm_parameters *p_params, + struct intel_crtc_state *cstate, + struct intel_plane *intel_plane, uint16_t ddb_allocation, int level, uint16_t *out_blocks, /* out */ uint8_t *out_lines /* out */) { + struct drm_plane *plane = &intel_plane->base; + struct drm_framebuffer *fb = plane->state->fb; uint32_t latency = dev_priv->wm.skl_latency[level]; uint32_t method1, method2; uint32_t plane_bytes_per_line, plane_blocks_per_line; @@ -3198,31 +3179,35 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint32_t selected_result; uint8_t bytes_per_pixel; - if (latency == 0 || !p->active || !p_params->enabled) + if (latency == 0 || !cstate->base.active || !fb) return false; - bytes_per_pixel = p_params->y_bytes_per_pixel ? - p_params->y_bytes_per_pixel : - p_params->bytes_per_pixel; - method1 = skl_wm_method1(p->pixel_rate, + bytes_per_pixel = (fb->pixel_format == DRM_FORMAT_NV12) ? + drm_format_plane_cpp(DRM_FORMAT_NV12, 0) : + drm_format_plane_cpp(DRM_FORMAT_NV12, 1); + method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate), bytes_per_pixel, latency); - method2 = skl_wm_method2(p->pixel_rate, - p->pipe_htotal, - p_params->horiz_pixels, + method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate), + cstate->base.adjusted_mode.crtc_htotal, + cstate->pipe_src_w, bytes_per_pixel, - p_params->tiling, + fb->modifier[0], latency); - plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel; + plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel; plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512); - if (p_params->tiling == I915_FORMAT_MOD_Y_TILED || - p_params->tiling == I915_FORMAT_MOD_Yf_TILED) { + if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || + fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { uint32_t min_scanlines = 4; uint32_t y_tile_minimum; - if (intel_rotation_90_or_270(p_params->rotation)) { - switch (p_params->bytes_per_pixel) { + if (intel_rotation_90_or_270(plane->state->rotation)) { + int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ? + drm_format_plane_cpp(fb->pixel_format, 1) : + drm_format_plane_cpp(fb->pixel_format, 0); + + switch (bpp) { case 1: min_scanlines = 16; break; @@ -3246,8 +3231,8 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line); if (level >= 1 && level <= 7) { - if (p_params->tiling == I915_FORMAT_MOD_Y_TILED || - p_params->tiling == I915_FORMAT_MOD_Yf_TILED) + if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || + fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) res_lines += 4; else res_blocks++; @@ -3264,84 +3249,80 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, static void skl_compute_wm_level(const struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb, - struct skl_pipe_wm_parameters *p, - enum pipe pipe, + struct intel_crtc_state *cstate, int level, - int num_planes, struct skl_wm_level *result) { + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); + struct intel_plane *intel_plane; uint16_t ddb_blocks; - int i; + enum pipe pipe = intel_crtc->pipe; + + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + int i = skl_wm_plane_id(intel_plane); - for (i = 0; i < num_planes; i++) { ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]); result->plane_en[i] = skl_compute_plane_wm(dev_priv, - p, &p->plane[i], + cstate, + intel_plane, ddb_blocks, level, &result->plane_res_b[i], &result->plane_res_l[i]); } - - ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]); - result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p, - &p->plane[PLANE_CURSOR], - ddb_blocks, level, - &result->plane_res_b[PLANE_CURSOR], - &result->plane_res_l[PLANE_CURSOR]); } static uint32_t -skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) +skl_compute_linetime_wm(struct intel_crtc_state *cstate) { - if (!to_intel_crtc(crtc)->active) + if (!cstate->base.active) return 0; - if (WARN_ON(p->pixel_rate == 0)) + if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0)) return 0; - return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); + return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000, + skl_pipe_pixel_rate(cstate)); } -static void skl_compute_transition_wm(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *params, +static void skl_compute_transition_wm(struct intel_crtc_state *cstate, struct skl_wm_level *trans_wm /* out */) { + struct drm_crtc *crtc = cstate->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int i; + struct intel_plane *intel_plane; - if (!params->active) + if (!cstate->base.active) return; /* Until we know more, just disable transition WMs */ - for (i = 0; i < intel_num_planes(intel_crtc); i++) + for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) { + int i = skl_wm_plane_id(intel_plane); + trans_wm->plane_en[i] = false; - trans_wm->plane_en[PLANE_CURSOR] = false; + } } -static void skl_compute_pipe_wm(struct drm_crtc *crtc, +static void skl_compute_pipe_wm(struct intel_crtc_state *cstate, struct skl_ddb_allocation *ddb, - struct skl_pipe_wm_parameters *params, struct skl_pipe_wm *pipe_wm) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = cstate->base.crtc->dev; const struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int level, max_level = ilk_wm_max_level(dev); for (level = 0; level <= max_level; level++) { - skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe, - level, intel_num_planes(intel_crtc), - &pipe_wm->wm[level]); + skl_compute_wm_level(dev_priv, ddb, cstate, + level, &pipe_wm->wm[level]); } - pipe_wm->linetime = skl_compute_linetime_wm(crtc, params); + pipe_wm->linetime = skl_compute_linetime_wm(cstate); - skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm); + skl_compute_transition_wm(cstate, &pipe_wm->trans_wm); } static void skl_compute_wm_results(struct drm_device *dev, - struct skl_pipe_wm_parameters *p, struct skl_pipe_wm *p_wm, struct skl_wm_values *r, struct intel_crtc *intel_crtc) @@ -3585,16 +3566,15 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, } static bool skl_update_pipe_wm(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *params, struct intel_wm_config *config, struct skl_ddb_allocation *ddb, /* out */ struct skl_pipe_wm *pipe_wm /* out */) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - skl_compute_wm_pipe_parameters(crtc, params); - skl_allocate_pipe_ddb(crtc, config, params, ddb); - skl_compute_pipe_wm(crtc, ddb, params, pipe_wm); + skl_allocate_pipe_ddb(cstate, config, ddb); + skl_compute_pipe_wm(cstate, ddb, pipe_wm); if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) return false; @@ -3627,7 +3607,6 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, */ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { - struct skl_pipe_wm_parameters params = {}; struct skl_pipe_wm pipe_wm = {}; bool wm_changed; @@ -3637,8 +3616,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, if (!intel_crtc->active) continue; - wm_changed = skl_update_pipe_wm(&intel_crtc->base, - ¶ms, config, + wm_changed = skl_update_pipe_wm(&intel_crtc->base, config, &r->ddb, &pipe_wm); /* @@ -3648,7 +3626,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, */ WARN_ON(!wm_changed); - skl_compute_wm_results(dev, ¶ms, &pipe_wm, r, intel_crtc); + skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc); r->dirty[intel_crtc->pipe] = true; } } @@ -3678,7 +3656,6 @@ static void skl_update_wm(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct skl_pipe_wm_parameters params = {}; struct skl_wm_values *results = &dev_priv->wm.skl_results; struct skl_pipe_wm pipe_wm = {}; struct intel_wm_config config = {}; @@ -3691,11 +3668,10 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_compute_wm_global_parameters(dev, &config); - if (!skl_update_pipe_wm(crtc, ¶ms, &config, - &results->ddb, &pipe_wm)) + if (!skl_update_pipe_wm(crtc, &config, &results->ddb, &pipe_wm)) return; - skl_compute_wm_results(dev, ¶ms, &pipe_wm, results, intel_crtc); + skl_compute_wm_results(dev, &pipe_wm, results, intel_crtc); results->dirty[intel_crtc->pipe] = true; skl_update_other_pipe_wm(dev, crtc, &config, results); From 7809e5ae35b9d8d0710f0874b2e3f10be144e38b Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:12 -0700 Subject: [PATCH 071/134] drm/i915/ivb: Move WaCxSRDisabledForSpriteScaling w/a to atomic check Determine whether we need to apply this workaround at atomic check time and just set a flag that will be used by the main watermark update routine. Moving this workaround into the atomic framework reduces ilk_update_sprite_wm() to just a standard watermark update, so drop it completely and just ensure that ilk_update_wm() is called whenever a sprite plane is updated in a way that would affect watermarks. Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 1 + drivers/gpu/drm/i915/intel_display.c | 39 +++++++++++++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 35 +++++++++---------------- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index f1975f267710..05b12032d262 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -94,6 +94,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); crtc_state->update_pipe = false; + crtc_state->disable_lp_wm = false; return &crtc_state->base; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 305abaa0d000..d3dab99f3220 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11574,18 +11574,32 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, static bool intel_wm_need_update(struct drm_plane *plane, struct drm_plane_state *state) { - /* Update watermarks on tiling changes. */ + struct intel_plane_state *new = to_intel_plane_state(state); + struct intel_plane_state *cur = to_intel_plane_state(plane->state); + + /* Update watermarks on tiling or size changes. */ if (!plane->state->fb || !state->fb || plane->state->fb->modifier[0] != state->fb->modifier[0] || - plane->state->rotation != state->rotation) - return true; - - if (plane->state->crtc_w != state->crtc_w) + plane->state->rotation != state->rotation || + drm_rect_width(&new->src) != drm_rect_width(&cur->src) || + drm_rect_height(&new->src) != drm_rect_height(&cur->src) || + drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) || + drm_rect_height(&new->dst) != drm_rect_height(&cur->dst)) return true; return false; } +static bool needs_scaling(struct intel_plane_state *state) +{ + int src_w = drm_rect_width(&state->src) >> 16; + int src_h = drm_rect_height(&state->src) >> 16; + int dst_w = drm_rect_width(&state->dst); + int dst_h = drm_rect_height(&state->dst); + + return (src_w != dst_w || src_h != dst_h); +} + int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) { @@ -11601,7 +11615,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, bool mode_changed = needs_modeset(crtc_state); bool was_crtc_enabled = crtc->state->active; bool is_crtc_enabled = crtc_state->active; - bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb; @@ -11719,11 +11732,23 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, case DRM_PLANE_TYPE_CURSOR: break; case DRM_PLANE_TYPE_OVERLAY: - if (turn_off && !mode_changed) { + /* + * WaCxSRDisabledForSpriteScaling:ivb + * + * cstate->update_wm was already set above, so this flag will + * take effect when we commit and program watermarks. + */ + if (IS_IVYBRIDGE(dev) && + needs_scaling(to_intel_plane_state(plane_state)) && + !needs_scaling(old_plane_state)) { + to_intel_crtc_state(crtc_state)->disable_lp_wm = true; + } else if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; } + + break; } return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1eaa9f91bcb7..d6d7ac73f645 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -466,6 +466,9 @@ struct intel_crtc_state { /* w/a for waiting 2 vblanks during crtc enable */ enum pipe hsw_workaround_pipe; + + /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */ + bool disable_lp_wm; }; struct vlv_wm_state { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3aca66d99353..b8c3e2206191 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3730,6 +3730,18 @@ static void ilk_update_wm(struct drm_crtc *crtc) WARN_ON(cstate->base.active != intel_crtc->active); + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + * + * WaCxSRDisabledForSpriteScaling:ivb + */ + if (cstate->disable_lp_wm) { + ilk_disable_lp_wm(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); + } + intel_compute_pipe_wm(cstate, &pipe_wm); if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) @@ -3761,28 +3773,6 @@ static void ilk_update_wm(struct drm_crtc *crtc) ilk_write_wm_values(dev_priv, &results); } -static void -ilk_update_sprite_wm(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, uint32_t sprite_height, - int pixel_size, bool enabled, bool scaled) -{ - struct drm_device *dev = plane->dev; - struct intel_plane *intel_plane = to_intel_plane(plane); - - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - * - * WaCxSRDisabledForSpriteScaling:ivb - */ - if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev)) - intel_wait_for_vblank(dev, intel_plane->pipe); - - ilk_update_wm(crtc); -} - static void skl_pipe_wm_active_state(uint32_t val, struct skl_pipe_wm *active, bool is_transwm, @@ -7108,7 +7098,6 @@ void intel_init_pm(struct drm_device *dev) (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.update_wm = ilk_update_wm; - dev_priv->display.update_sprite_wm = ilk_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); From 47c99438b52d12df50e182583634a4cfede3c920 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:13 -0700 Subject: [PATCH 072/134] drm/i915: Drop intel_update_sprite_watermarks The only platform that still has an update_sprite_wm entrypoint is SKL; on SKL, intel_update_sprite_watermarks just updates intel_plane->wm and then performs a regular watermark update. However intel_plane->wm is only used to update a couple fields in intel_wm_config, and those fields are never used by the SKL code, so on SKL an update_sprite_wm is effectively identical to an update_wm call. Since we're already ensuring that the regular intel_update_wm is called any time we'd try to call intel_update_sprite_watermarks, the whole call is redundant and can be dropped. Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 -- drivers/gpu/drm/i915/intel_display.c | 5 --- drivers/gpu/drm/i915/intel_drv.h | 6 --- drivers/gpu/drm/i915/intel_pm.c | 58 ---------------------------- drivers/gpu/drm/i915/intel_sprite.c | 15 ------- 5 files changed, 88 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 29ce11fc2408..268abbcd6c8c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -628,10 +628,6 @@ struct drm_i915_display_funcs { struct dpll *match_clock, struct dpll *best_clock); void (*update_wm)(struct drm_crtc *crtc); - void (*update_sprite_wm)(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, uint32_t sprite_height, - int pixel_size, bool enable, bool scaled); int (*modeset_calc_cdclk)(struct drm_atomic_state *state); void (*modeset_commit_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d3dab99f3220..da894dba56dd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4805,7 +4805,6 @@ static void intel_post_plane_update(struct intel_crtc *crtc) struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_plane *plane; if (atomic->wait_vblank) intel_wait_for_vblank(dev, crtc->pipe); @@ -4824,10 +4823,6 @@ static void intel_post_plane_update(struct intel_crtc *crtc) if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); - drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks) - intel_update_sprite_watermarks(plane, &crtc->base, - 0, 0, 0, false, false); - memset(atomic, 0, sizeof(*atomic)); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d6d7ac73f645..9431a12c4204 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1398,12 +1398,6 @@ void intel_init_clock_gating(struct drm_device *dev); void intel_suspend_hw(struct drm_device *dev); int ilk_wm_max_level(const struct drm_device *dev); void intel_update_watermarks(struct drm_crtc *crtc); -void intel_update_sprite_watermarks(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, - uint32_t sprite_height, - int pixel_size, - bool enabled, bool scaled); void intel_init_pm(struct drm_device *dev); void intel_pm_setup(struct drm_device *dev); void intel_gpu_ips_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b8c3e2206191..6de3ef36754b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3148,18 +3148,9 @@ static void skl_compute_wm_global_parameters(struct drm_device *dev, struct intel_wm_config *config) { struct drm_crtc *crtc; - struct drm_plane *plane; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) config->num_pipes_active += to_intel_crtc(crtc)->active; - - /* FIXME: I don't think we need those two global parameters on SKL */ - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - struct intel_plane *intel_plane = to_intel_plane(plane); - - config->sprites_enabled |= intel_plane->wm.enabled; - config->sprites_scaled |= intel_plane->wm.scaled; - } } static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, @@ -3682,39 +3673,6 @@ static void skl_update_wm(struct drm_crtc *crtc) dev_priv->wm.skl_hw = *results; } -static void -skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc, - uint32_t sprite_width, uint32_t sprite_height, - int pixel_size, bool enabled, bool scaled) -{ - struct intel_plane *intel_plane = to_intel_plane(plane); - struct drm_framebuffer *fb = plane->state->fb; - - intel_plane->wm.enabled = enabled; - intel_plane->wm.scaled = scaled; - intel_plane->wm.horiz_pixels = sprite_width; - intel_plane->wm.vert_pixels = sprite_height; - intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE; - - /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */ - intel_plane->wm.bytes_per_pixel = - (fb && fb->pixel_format == DRM_FORMAT_NV12) ? - drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size; - intel_plane->wm.y_bytes_per_pixel = - (fb && fb->pixel_format == DRM_FORMAT_NV12) ? - drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0; - - /* - * Framebuffer can be NULL on plane disable, but it does not - * matter for watermarks if we assume no tiling in that case. - */ - if (fb) - intel_plane->wm.tiling = fb->modifier[0]; - intel_plane->wm.rotation = plane->state->rotation; - - skl_update_wm(crtc); -} - static void ilk_update_wm(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -4150,21 +4108,6 @@ void intel_update_watermarks(struct drm_crtc *crtc) dev_priv->display.update_wm(crtc); } -void intel_update_sprite_watermarks(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, - uint32_t sprite_height, - int pixel_size, - bool enabled, bool scaled) -{ - struct drm_i915_private *dev_priv = plane->dev->dev_private; - - if (dev_priv->display.update_sprite_wm) - dev_priv->display.update_sprite_wm(plane, crtc, - sprite_width, sprite_height, - pixel_size, enabled, scaled); -} - /** * Lock protecting IPS related data structures */ @@ -7089,7 +7032,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = skl_init_clock_gating; dev_priv->display.update_wm = skl_update_wm; - dev_priv->display.update_sprite_wm = skl_update_sprite_wm; } else if (HAS_PCH_SPLIT(dev)) { ilk_setup_wm_latency(dev); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b229c6752671..dd2d5683fcb1 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -192,7 +192,6 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, const int pipe = intel_plane->pipe; const int plane = intel_plane->plane + 1; u32 plane_ctl, stride_div, stride; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &to_intel_plane_state(drm_plane->state)->ckey; unsigned long surf_addr; @@ -211,10 +210,6 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, rotation = drm_plane->state->rotation; plane_ctl |= skl_plane_ctl_rotation(rotation); - intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h, - pixel_size, true, - src_w != crtc_w || src_h != crtc_h); - stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], fb->pixel_format); @@ -296,8 +291,6 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) I915_WRITE(PLANE_SURF(pipe, plane), 0); POSTING_READ(PLANE_SURF(pipe, plane)); - - intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } static void @@ -540,10 +533,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (IS_HASWELL(dev) || IS_BROADWELL(dev)) sprctl |= SPRITE_PIPE_CSC_ENABLE; - intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size, - true, - src_w != crtc_w || src_h != crtc_h); - /* Sizes are 0 based */ src_w--; src_h--; @@ -677,10 +666,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (IS_GEN6(dev)) dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ - intel_update_sprite_watermarks(plane, crtc, src_w, src_h, - pixel_size, true, - src_w != crtc_w || src_h != crtc_h); - /* Sizes are 0 based */ src_w--; src_h--; From de165e0bccb4a8fe71debd5adb2f599609bcb8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Sep 2015 15:53:14 -0700 Subject: [PATCH 073/134] drm/i915: Refactor ilk_update_wm (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split ilk_update_wm() into two parts; one doing the programming and the other the calculations. v2: Fix typo in commit message v3 (by Matt): Heavily rebased for current codebase. Signed-off-by: Ville Syrjälä Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 64 ++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6de3ef36754b..2f064de550ab 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3673,39 +3673,14 @@ static void skl_update_wm(struct drm_crtc *crtc) dev_priv->wm.skl_hw = *results; } -static void ilk_update_wm(struct drm_crtc *crtc) +static void ilk_program_watermarks(struct drm_i915_private *dev_priv) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_device *dev = dev_priv->dev; + struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct ilk_wm_maximums max; + struct intel_wm_config config = {}; struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; - struct intel_pipe_wm pipe_wm = {}; - struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; - struct intel_wm_config config = {}; - - WARN_ON(cstate->base.active != intel_crtc->active); - - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - * - * WaCxSRDisabledForSpriteScaling:ivb - */ - if (cstate->disable_lp_wm) { - ilk_disable_lp_wm(dev); - intel_wait_for_vblank(dev, intel_crtc->pipe); - } - - intel_compute_pipe_wm(cstate, &pipe_wm); - - if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) - return; - - intel_crtc->wm.active = pipe_wm; ilk_compute_wm_config(dev, &config); @@ -3731,6 +3706,37 @@ static void ilk_update_wm(struct drm_crtc *crtc) ilk_write_wm_values(dev_priv, &results); } +static void ilk_update_wm(struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct intel_pipe_wm pipe_wm = {}; + + WARN_ON(cstate->base.active != intel_crtc->active); + + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + * + * WaCxSRDisabledForSpriteScaling:ivb + */ + if (cstate->disable_lp_wm) { + ilk_disable_lp_wm(crtc->dev); + intel_wait_for_vblank(crtc->dev, intel_crtc->pipe); + } + + intel_compute_pipe_wm(cstate, &pipe_wm); + + if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) + return; + + intel_crtc->wm.active = pipe_wm; + + ilk_program_watermarks(dev_priv); +} + static void skl_pipe_wm_active_state(uint32_t val, struct skl_pipe_wm *active, bool is_transwm, From de4a9f83395e8a709ffe463dff6d1c51945da352 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:15 -0700 Subject: [PATCH 074/134] drm/i915: Calculate pipe watermarks into CRTC state (v3) A future patch will calculate these during the atomic 'check' phase rather than at WM programming time, so let's store the watermark values we're planning to use in the CRTC state; the values actually active on the hardware remains in intel_crtc. While we're at it, do some minor restructuring to keep ILK and SKL values in a union. v2: Don't move cxsr_allowed to state (Maarten) v3: Only calculate watermarks in state. Still keep active watermarks in intel_crtc itself. (Ville) Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 48 ++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_pm.c | 44 ++++++++++++++++++----------- 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9431a12c4204..47732929c3e4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -332,6 +332,21 @@ struct intel_crtc_scaler_state { /* drm_mode->private_flags */ #define I915_MODE_FLAG_INHERITED 1 +struct intel_pipe_wm { + struct intel_wm_level wm[5]; + uint32_t linetime; + bool fbc_wm_enabled; + bool pipe_enabled; + bool sprites_enabled; + bool sprites_scaled; +}; + +struct skl_pipe_wm { + struct skl_wm_level wm[8]; + struct skl_wm_level trans_wm; + uint32_t linetime; +}; + struct intel_crtc_state { struct drm_crtc_state base; @@ -469,6 +484,17 @@ struct intel_crtc_state { /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */ bool disable_lp_wm; + + struct { + /* + * optimal watermarks, programmed post-vblank when this state + * is committed + */ + union { + struct intel_pipe_wm ilk; + struct skl_pipe_wm skl; + } optimal; + } wm; }; struct vlv_wm_state { @@ -480,15 +506,6 @@ struct vlv_wm_state { bool cxsr; }; -struct intel_pipe_wm { - struct intel_wm_level wm[5]; - uint32_t linetime; - bool fbc_wm_enabled; - bool pipe_enabled; - bool sprites_enabled; - bool sprites_scaled; -}; - struct intel_mmio_flip { struct work_struct work; struct drm_i915_private *i915; @@ -496,12 +513,6 @@ struct intel_mmio_flip { struct intel_crtc *crtc; }; -struct skl_pipe_wm { - struct skl_wm_level wm[8]; - struct skl_wm_level trans_wm; - uint32_t linetime; -}; - /* * Tracking of operations that need to be performed at the beginning/end of an * atomic commit, outside the atomic section where interrupts are disabled. @@ -569,9 +580,10 @@ struct intel_crtc { /* per-pipe watermark state */ struct { /* watermarks currently being used */ - struct intel_pipe_wm active; - /* SKL wm values currently in use */ - struct skl_pipe_wm skl_active; + union { + struct intel_pipe_wm ilk; + struct skl_pipe_wm skl; + } active; /* allow CxSR on this pipe */ bool cxsr_allowed; } wm; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2f064de550ab..3857592dbf0f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2331,7 +2331,7 @@ static void ilk_compute_wm_config(struct drm_device *dev, /* Compute the currently _active_ config */ for_each_intel_crtc(dev, intel_crtc) { - const struct intel_pipe_wm *wm = &intel_crtc->wm.active; + const struct intel_pipe_wm *wm = &intel_crtc->wm.active.ilk; if (!wm->pipe_enabled) continue; @@ -2428,7 +2428,9 @@ static void ilk_merge_wm_level(struct drm_device *dev, ret_wm->enable = true; for_each_intel_crtc(dev, intel_crtc) { - const struct intel_pipe_wm *active = &intel_crtc->wm.active; + const struct intel_crtc_state *cstate = + to_intel_crtc_state(intel_crtc->base.state); + const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk; const struct intel_wm_level *wm = &active->wm[level]; if (!active->pipe_enabled) @@ -2576,14 +2578,15 @@ static void ilk_compute_wm_results(struct drm_device *dev, /* LP0 register values */ for_each_intel_crtc(dev, intel_crtc) { + const struct intel_crtc_state *cstate = + to_intel_crtc_state(intel_crtc->base.state); enum pipe pipe = intel_crtc->pipe; - const struct intel_wm_level *r = - &intel_crtc->wm.active.wm[0]; + const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0]; if (WARN_ON(!r->enable)) continue; - results->wm_linetime[pipe] = intel_crtc->wm.active.linetime; + results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime; results->wm_pipe[pipe] = (r->pri_val << WM0_PIPE_PLANE_SHIFT) | @@ -3567,10 +3570,10 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc, skl_allocate_pipe_ddb(cstate, config, ddb); skl_compute_pipe_wm(cstate, ddb, pipe_wm); - if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) + if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm))) return false; - intel_crtc->wm.skl_active = *pipe_wm; + intel_crtc->wm.active.skl = *pipe_wm; return true; } @@ -3648,7 +3651,8 @@ static void skl_update_wm(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct skl_wm_values *results = &dev_priv->wm.skl_results; - struct skl_pipe_wm pipe_wm = {}; + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl; struct intel_wm_config config = {}; @@ -3659,10 +3663,10 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_compute_wm_global_parameters(dev, &config); - if (!skl_update_pipe_wm(crtc, &config, &results->ddb, &pipe_wm)) + if (!skl_update_pipe_wm(crtc, &config, &results->ddb, pipe_wm)) return; - skl_compute_wm_results(dev, &pipe_wm, results, intel_crtc); + skl_compute_wm_results(dev, pipe_wm, results, intel_crtc); results->dirty[intel_crtc->pipe] = true; skl_update_other_pipe_wm(dev, crtc, &config, results); @@ -3711,7 +3715,6 @@ static void ilk_update_wm(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - struct intel_pipe_wm pipe_wm = {}; WARN_ON(cstate->base.active != intel_crtc->active); @@ -3727,12 +3730,13 @@ static void ilk_update_wm(struct drm_crtc *crtc) intel_wait_for_vblank(crtc->dev, intel_crtc->pipe); } - intel_compute_pipe_wm(cstate, &pipe_wm); + intel_compute_pipe_wm(cstate, &cstate->wm.optimal.ilk); - if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) - return; + if (!memcmp(&intel_crtc->wm.active.ilk, + &cstate->wm.optimal.ilk, + sizeof(cstate->wm.optimal.ilk))); - intel_crtc->wm.active = pipe_wm; + intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk; ilk_program_watermarks(dev_priv); } @@ -3787,7 +3791,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct skl_wm_values *hw = &dev_priv->wm.skl_hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct skl_pipe_wm *active = &intel_crtc->wm.skl_active; + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct skl_pipe_wm *active = &cstate->wm.optimal.skl; enum pipe pipe = intel_crtc->pipe; int level, i, max_level; uint32_t temp; @@ -3831,6 +3836,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) temp = hw->plane_trans[pipe][PLANE_CURSOR]; skl_pipe_wm_active_state(temp, active, true, true, i, 0); + + intel_crtc->wm.active.skl = *active; } void skl_wm_get_hw_state(struct drm_device *dev) @@ -3850,7 +3857,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct ilk_wm_values *hw = &dev_priv->wm.hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_pipe_wm *active = &intel_crtc->wm.active; + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct intel_pipe_wm *active = &cstate->wm.optimal.ilk; enum pipe pipe = intel_crtc->pipe; static const unsigned int wm0_pipe_reg[] = { [PIPE_A] = WM0_PIPEA_ILK, @@ -3889,6 +3897,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) for (level = 0; level <= max_level; level++) active->wm[level].enable = true; } + + intel_crtc->wm.active.ilk = *active; } #define _FW_WM(value, plane) \ From a28170f3389f4e42db95e595b0d86384a79de696 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:16 -0700 Subject: [PATCH 075/134] drm/i915: Calculate ILK-style watermarks during atomic check (v3) Calculate pipe watermarks during atomic calculation phase, based on the contents of the atomic transaction's state structure. We still program the watermarks at the same time we did before, but the computation now happens much earlier. While this patch isn't too exciting by itself, it paves the way for future patches. The eventual goal (which will be realized in future patches in this series) is to calculate multiple sets up watermark values up front, and then program them at different times (pre- vs post-vblank) on the platforms that need a two-step watermark update. While we're at it, s/intel_compute_pipe_wm/ilk_compute_pipe_wm/ since this function only applies to ILK-style watermarks and we have a completely different function for SKL-style watermarks. Note that the original code had a memcmp() in ilk_update_wm() to avoid calling ilk_program_watermarks() if the watermarks hadn't changed. This memcmp vanishes here, which means we may do some unnecessary result generation and merging in cases where watermarks didn't change, but the lower-level function ilk_write_wm_values already makes sure that we don't actually try to program the watermark registers again. v2: Squash a few commits from the original series together; no longer leave pre-calculated wm's in a separate temporary structure since it's easier to follow the logic if we just cut over to using the pre-calculated values directly. v3: - Pass intel_crtc instead of drm_crtc to .compute_pipe_wm() entrypoint and use intel_atomic_get_crtc_state() to avoid need for extra casting. (Ander) - Drop unused intel_check_crtc() function prototype. (Ander) Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 6 ++ drivers/gpu/drm/i915/intel_pm.c | 88 ++++++++++++++-------------- 3 files changed, 51 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 268abbcd6c8c..00fef94d285b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -627,6 +627,8 @@ struct drm_i915_display_funcs { int target, int refclk, struct dpll *match_clock, struct dpll *best_clock); + int (*compute_pipe_wm)(struct intel_crtc *crtc, + struct drm_atomic_state *state); void (*update_wm)(struct drm_crtc *crtc); int (*modeset_calc_cdclk)(struct drm_atomic_state *state); void (*modeset_commit_cdclk)(struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index da894dba56dd..f293de83ca9a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11828,6 +11828,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } ret = 0; + if (dev_priv->display.compute_pipe_wm) { + ret = dev_priv->display.compute_pipe_wm(intel_crtc, state); + if (ret) + return ret; + } + if (INTEL_INFO(dev)->gen >= 9) { if (mode_changed) ret = skl_update_scaler_crtc(pipe_config); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3857592dbf0f..52c8b6aa5e0e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2029,9 +2029,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, const struct intel_crtc *intel_crtc, int level, struct intel_crtc_state *cstate, + struct intel_plane_state *pristate, + struct intel_plane_state *sprstate, + struct intel_plane_state *curstate, struct intel_wm_level *result) { - struct intel_plane *intel_plane; uint16_t pri_latency = dev_priv->wm.pri_latency[level]; uint16_t spr_latency = dev_priv->wm.spr_latency[level]; uint16_t cur_latency = dev_priv->wm.cur_latency[level]; @@ -2043,29 +2045,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, cur_latency *= 5; } - for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) { - struct intel_plane_state *pstate = - to_intel_plane_state(intel_plane->base.state); - - switch (intel_plane->base.type) { - case DRM_PLANE_TYPE_PRIMARY: - result->pri_val = ilk_compute_pri_wm(cstate, pstate, - pri_latency, - level); - result->fbc_val = ilk_compute_fbc_wm(cstate, pstate, - result->pri_val); - break; - case DRM_PLANE_TYPE_OVERLAY: - result->spr_val = ilk_compute_spr_wm(cstate, pstate, - spr_latency); - break; - case DRM_PLANE_TYPE_CURSOR: - result->cur_val = ilk_compute_cur_wm(cstate, pstate, - cur_latency); - break; - } - } - + result->pri_val = ilk_compute_pri_wm(cstate, pristate, + pri_latency, level); + result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency); + result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency); + result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val); result->enable = true; } @@ -2343,15 +2327,18 @@ static void ilk_compute_wm_config(struct drm_device *dev, } /* Compute new watermarks for the pipe */ -static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, - struct intel_pipe_wm *pipe_wm) +static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, + struct drm_atomic_state *state) { - struct drm_crtc *crtc = cstate->base.crtc; - struct drm_device *dev = crtc->dev; + struct intel_pipe_wm *pipe_wm; + struct drm_device *dev = intel_crtc->base.dev; const struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = NULL; struct intel_plane *intel_plane; + struct drm_plane_state *ps; + struct intel_plane_state *pristate = NULL; struct intel_plane_state *sprstate = NULL; + struct intel_plane_state *curstate = NULL; int level, max_level = ilk_wm_max_level(dev); /* LP0 watermark maximums depend on this pipe alone */ struct intel_wm_config config = { @@ -2359,11 +2346,24 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, }; struct ilk_wm_maximums max; + cstate = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(cstate)) + return PTR_ERR(cstate); + + pipe_wm = &cstate->wm.optimal.ilk; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) { - sprstate = to_intel_plane_state(intel_plane->base.state); - break; - } + ps = drm_atomic_get_plane_state(state, + &intel_plane->base); + if (IS_ERR(ps)) + return PTR_ERR(ps); + + if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY) + pristate = to_intel_plane_state(ps); + else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) + sprstate = to_intel_plane_state(ps); + else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR) + curstate = to_intel_plane_state(ps); } config.sprites_enabled = sprstate->visible; @@ -2372,7 +2372,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16); pipe_wm->pipe_enabled = cstate->base.active; - pipe_wm->sprites_enabled = sprstate->visible; + pipe_wm->sprites_enabled = config.sprites_enabled; pipe_wm->sprites_scaled = config.sprites_scaled; /* ILK/SNB: LP2+ watermarks only w/o sprites */ @@ -2383,24 +2383,27 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, if (config.sprites_scaled) max_level = 0; - ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]); + ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, + pristate, sprstate, curstate, &pipe_wm->wm[0]); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); + pipe_wm->linetime = hsw_compute_linetime_wm(dev, + &intel_crtc->base); /* LP0 watermarks always use 1/2 DDB partitioning */ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); /* At least LP0 must be valid */ if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) - return false; + return -EINVAL; ilk_compute_wm_reg_maximums(dev, 1, &max); for (level = 1; level <= max_level; level++) { struct intel_wm_level wm = {}; - ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm); + ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, + pristate, sprstate, curstate, &wm); /* * Disable any watermark level that exceeds the @@ -2413,7 +2416,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, pipe_wm->wm[level] = wm; } - return true; + return 0; } /* @@ -3730,12 +3733,6 @@ static void ilk_update_wm(struct drm_crtc *crtc) intel_wait_for_vblank(crtc->dev, intel_crtc->pipe); } - intel_compute_pipe_wm(cstate, &cstate->wm.optimal.ilk); - - if (!memcmp(&intel_crtc->wm.active.ilk, - &cstate->wm.optimal.ilk, - sizeof(cstate->wm.optimal.ilk))); - intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk; ilk_program_watermarks(dev_priv); @@ -7056,6 +7053,7 @@ void intel_init_pm(struct drm_device *dev) (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.update_wm = ilk_update_wm; + dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); From a4611e444694869a9ccec69e4e640aee9b7dc58e Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:17 -0700 Subject: [PATCH 076/134] drm/i915: Don't set plane visible during HW readout if CRTC is off We already ensure that pstate->visible = false when crtc->active = false during runtime programming; make sure we follow the same logic when reading out initial hardware state. Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f293de83ca9a..b6a68bd1743c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15166,7 +15166,7 @@ static void readout_plane_state(struct intel_crtc *crtc) struct intel_plane_state *plane_state = to_intel_plane_state(primary->state); - plane_state->visible = + plane_state->visible = crtc->active && primary_get_hw_state(to_intel_plane(primary)); if (plane_state->visible) From 76305b1a68e196c4f76d15ec1897097bb7a7c641 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 24 Sep 2015 15:53:18 -0700 Subject: [PATCH 077/134] drm/i915: Calculate watermark configuration during atomic check (v2) v2: Don't forget to actually check the cstate->active value when tallying up the number of active CRTC's. (Ander) Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 +++++ drivers/gpu/drm/i915/intel_display.c | 52 ++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 64 ++++++---------------------- 4 files changed, 72 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 00fef94d285b..b17dac647787 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1692,6 +1692,13 @@ struct i915_execbuffer_params { struct drm_i915_gem_request *request; }; +/* used in computing the new watermarks state */ +struct intel_wm_config { + unsigned int num_pipes_active; + bool sprites_enabled; + bool sprites_scaled; +}; + struct drm_i915_private { struct drm_device *dev; struct kmem_cache *objects; @@ -1912,6 +1919,9 @@ struct drm_i915_private { */ uint16_t skl_latency[8]; + /* Committed wm config */ + struct intel_wm_config config; + /* * The skl_wm_values structure is a bit too big for stack * allocation, so we keep the staging struct where we store diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b6a68bd1743c..bbeb6d3aca1e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13039,6 +13039,45 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return 0; } +/* + * Handle calculation of various watermark data at the end of the atomic check + * phase. The code here should be run after the per-crtc and per-plane 'check' + * handlers to ensure that all derived state has been updated. + */ +static void calc_watermark_data(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + struct drm_crtc *crtc; + struct drm_crtc_state *cstate; + struct drm_plane *plane; + struct drm_plane_state *pstate; + + /* + * Calculate watermark configuration details now that derived + * plane/crtc state is all properly updated. + */ + drm_for_each_crtc(crtc, dev) { + cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?: + crtc->state; + + if (cstate->active) + intel_state->wm_config.num_pipes_active++; + } + drm_for_each_legacy_plane(plane, dev) { + pstate = drm_atomic_get_existing_plane_state(state, plane) ?: + plane->state; + + if (!to_intel_plane_state(pstate)->visible) + continue; + + intel_state->wm_config.sprites_enabled = true; + if (pstate->crtc_w != pstate->src_w >> 16 || + pstate->crtc_h != pstate->src_h >> 16) + intel_state->wm_config.sprites_scaled = true; + } +} + /** * intel_atomic_check - validate state object * @dev: drm device @@ -13047,6 +13086,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state) static int intel_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; @@ -13110,10 +13150,15 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; } else - to_intel_atomic_state(state)->cdclk = - to_i915(state->dev)->cdclk_freq; + intel_state->cdclk = to_i915(state->dev)->cdclk_freq; - return drm_atomic_helper_check_planes(state->dev, state); + ret = drm_atomic_helper_check_planes(state->dev, state); + if (ret) + return ret; + + calc_watermark_data(state); + + return 0; } /** @@ -13153,6 +13198,7 @@ static int intel_atomic_commit(struct drm_device *dev, return ret; drm_atomic_helper_swap_state(dev, state); + dev_priv->wm.config = to_intel_atomic_state(state)->wm_config; for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 47732929c3e4..dfd2d10d3d3c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -248,6 +248,7 @@ struct intel_atomic_state { unsigned int cdclk; bool dpll_set; struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; + struct intel_wm_config wm_config; }; struct intel_plane_state { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 52c8b6aa5e0e..eb9a66d3a477 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1772,13 +1772,6 @@ struct ilk_wm_maximums { uint16_t fbc; }; -/* used in computing the new watermarks state */ -struct intel_wm_config { - unsigned int num_pipes_active; - bool sprites_enabled; - bool sprites_scaled; -}; - /* * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. @@ -2308,24 +2301,6 @@ static void skl_setup_wm_latency(struct drm_device *dev) intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency); } -static void ilk_compute_wm_config(struct drm_device *dev, - struct intel_wm_config *config) -{ - struct intel_crtc *intel_crtc; - - /* Compute the currently _active_ config */ - for_each_intel_crtc(dev, intel_crtc) { - const struct intel_pipe_wm *wm = &intel_crtc->wm.active.ilk; - - if (!wm->pipe_enabled) - continue; - - config->sprites_enabled |= wm->sprites_enabled; - config->sprites_scaled |= wm->sprites_scaled; - config->num_pipes_active++; - } -} - /* Compute new watermarks for the pipe */ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, struct drm_atomic_state *state) @@ -2971,11 +2946,12 @@ skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate) static void skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, - const struct intel_wm_config *config, struct skl_ddb_allocation *ddb /* out */) { struct drm_crtc *crtc = cstate->base.crtc; struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_wm_config *config = &dev_priv->wm.config; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane; enum pipe pipe = intel_crtc->pipe; @@ -3150,15 +3126,6 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb, return false; } -static void skl_compute_wm_global_parameters(struct drm_device *dev, - struct intel_wm_config *config) -{ - struct drm_crtc *crtc; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - config->num_pipes_active += to_intel_crtc(crtc)->active; -} - static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, struct intel_crtc_state *cstate, struct intel_plane *intel_plane, @@ -3563,14 +3530,13 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, } static bool skl_update_pipe_wm(struct drm_crtc *crtc, - struct intel_wm_config *config, struct skl_ddb_allocation *ddb, /* out */ struct skl_pipe_wm *pipe_wm /* out */) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - skl_allocate_pipe_ddb(cstate, config, ddb); + skl_allocate_pipe_ddb(cstate, ddb); skl_compute_pipe_wm(cstate, ddb, pipe_wm); if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm))) @@ -3583,7 +3549,6 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc, static void skl_update_other_pipe_wm(struct drm_device *dev, struct drm_crtc *crtc, - struct intel_wm_config *config, struct skl_wm_values *r) { struct intel_crtc *intel_crtc; @@ -3613,7 +3578,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, if (!intel_crtc->active) continue; - wm_changed = skl_update_pipe_wm(&intel_crtc->base, config, + wm_changed = skl_update_pipe_wm(&intel_crtc->base, &r->ddb, &pipe_wm); /* @@ -3656,7 +3621,6 @@ static void skl_update_wm(struct drm_crtc *crtc) struct skl_wm_values *results = &dev_priv->wm.skl_results; struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl; - struct intel_wm_config config = {}; /* Clear all dirty flags */ @@ -3664,15 +3628,13 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_clear_wm(results, intel_crtc->pipe); - skl_compute_wm_global_parameters(dev, &config); - - if (!skl_update_pipe_wm(crtc, &config, &results->ddb, pipe_wm)) + if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm)) return; skl_compute_wm_results(dev, pipe_wm, results, intel_crtc); results->dirty[intel_crtc->pipe] = true; - skl_update_other_pipe_wm(dev, crtc, &config, results); + skl_update_other_pipe_wm(dev, crtc, results); skl_write_wm_values(dev_priv, results); skl_flush_wm_values(dev_priv, results); @@ -3685,20 +3647,18 @@ static void ilk_program_watermarks(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct ilk_wm_maximums max; - struct intel_wm_config config = {}; + struct intel_wm_config *config = &dev_priv->wm.config; struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; - ilk_compute_wm_config(dev, &config); - - ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); - ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); + ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max); + ilk_wm_merge(dev, config, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_INFO(dev)->gen >= 7 && - config.num_pipes_active == 1 && config.sprites_enabled) { - ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); - ilk_wm_merge(dev, &config, &max, &lp_wm_5_6); + config->num_pipes_active == 1 && config->sprites_enabled) { + ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max); + ilk_wm_merge(dev, config, &max, &lp_wm_5_6); best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { From 923c124107840d58c5002cc19734310743501811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 30 Sep 2015 17:06:43 +0300 Subject: [PATCH 078/134] drm/i915: s/GET_CFG_CR1_REG/DPLL_CFGCR1/ etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Use SKL_DPLLx symbolic names instead of raw numbers Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++-- drivers/gpu/drm/i915/intel_ddi.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0b2e3148a5bf..9e3fdb372275 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7438,8 +7438,8 @@ enum skl_disp_power_wells { #define DPLL_CFGCR2_PDIV_7 (4<<2) #define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3) -#define GET_CFG_CR1_REG(id) (DPLL1_CFGCR1 + (id - SKL_DPLL1) * 8) -#define GET_CFG_CR2_REG(id) (DPLL1_CFGCR2 + (id - SKL_DPLL1) * 8) +#define DPLL_CFGCR1(id) (DPLL1_CFGCR1 + ((id) - SKL_DPLL1) * 8) +#define DPLL_CFGCR2(id) (DPLL1_CFGCR2 + ((id) - SKL_DPLL1) * 8) /* BXT display engine PLL */ #define BXT_DE_PLL_CTL 0x6d000 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9c115773ef4b..2d3cc82dd8a4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -969,8 +969,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, uint32_t cfgcr1_val, cfgcr2_val; uint32_t p0, p1, p2, dco_freq; - cfgcr1_reg = GET_CFG_CR1_REG(dpll); - cfgcr2_reg = GET_CFG_CR2_REG(dpll); + cfgcr1_reg = DPLL_CFGCR1(dpll); + cfgcr2_reg = DPLL_CFGCR2(dpll); cfgcr1_val = I915_READ(cfgcr1_reg); cfgcr2_val = I915_READ(cfgcr2_reg); @@ -2504,20 +2504,20 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = { { /* DPLL 1 */ .ctl = LCPLL2_CTL, - .cfgcr1 = DPLL1_CFGCR1, - .cfgcr2 = DPLL1_CFGCR2, + .cfgcr1 = DPLL_CFGCR1(SKL_DPLL1), + .cfgcr2 = DPLL_CFGCR2(SKL_DPLL1), }, { /* DPLL 2 */ .ctl = WRPLL_CTL1, - .cfgcr1 = DPLL2_CFGCR1, - .cfgcr2 = DPLL2_CFGCR2, + .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2), + .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2), }, { /* DPLL 3 */ .ctl = WRPLL_CTL2, - .cfgcr1 = DPLL3_CFGCR1, - .cfgcr2 = DPLL3_CFGCR2, + .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3), + .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3), }, }; From 9d91a1bfae7d12eb2c91006dc977d9bac9000a30 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Wed, 30 Sep 2015 09:57:37 -0700 Subject: [PATCH 079/134] drm/i915/guc: Don't forward flip interrupts to GuC Due to flip interrupts GuC stays awake always and GT does not enter RC6. Do not route those interrupts to GuC for now. Driver won't touch DE_GUCRMR register and leave it as what default value. Signed-off-by: Sagar Arun Kamble Signed-off-by: Alex Dai Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_guc_loader.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 5d17b63c107c..f87d833aa5ca 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -90,9 +90,6 @@ static void direct_interrupts_to_host(struct drm_i915_private *dev_priv) for_each_ring(ring, dev_priv, i) I915_WRITE(RING_MODE_GEN7(ring), irqs); - /* tell DE to send nothing to GuC */ - I915_WRITE(DE_GUCRMR, ~0); - /* route all GT interrupts to the host */ I915_WRITE(GUC_BCS_RCS_IER, 0); I915_WRITE(GUC_VCS2_VCS1_IER, 0); @@ -110,13 +107,6 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv) for_each_ring(ring, dev_priv, i) I915_WRITE(RING_MODE_GEN7(ring), irqs); - /* tell DE to send (all) flip_done to GuC */ - irqs = DERRMR_PIPEA_PRI_FLIP_DONE | DERRMR_PIPEA_SPR_FLIP_DONE | - DERRMR_PIPEB_PRI_FLIP_DONE | DERRMR_PIPEB_SPR_FLIP_DONE | - DERRMR_PIPEC_PRI_FLIP_DONE | DERRMR_PIPEC_SPR_FLIP_DONE; - /* Unmasked bits will cause GuC response message to be sent */ - I915_WRITE(DE_GUCRMR, ~irqs); - /* route USER_INTERRUPT to Host, all others are sent to GuC. */ irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; From 101b506a7fc7be3f0d0a337ade270eb5eb5a2857 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 1 Oct 2015 13:33:57 +0100 Subject: [PATCH 080/134] drm/i915: Wa32bitGeneralStateOffset & Wa32bitInstructionBaseOffset There are some allocations that must be only referenced by 32-bit offsets. To limit the chances of having the first 4GB already full, objects not requiring this workaround use DRM_MM_SEARCH_BELOW/ DRM_MM_CREATE_TOP flags In specific, any resource used with flat/heapless (0x00000000-0xfffff000) General State Heap (GSH) or Instruction State Heap (ISH) must be in a 32-bit range, because the General State Offset and Instruction State Offset are limited to 32-bits. Objects must have EXEC_OBJECT_SUPPORTS_48B_ADDRESS flag to indicate if they can be allocated above the 32-bit address range. To limit the chances of having the first 4GB already full, objects will use DRM_MM_SEARCH_BELOW + DRM_MM_CREATE_TOP flags when possible. The libdrm user of the EXEC_OBJECT_SUPPORTS_48B_ADDRESS flag is here: http://lists.freedesktop.org/archives/intel-gfx/2015-September/075836.html v2: Changed flag logic from neeeds_32b, to supports_48b. v3: Moved 48-bit support flag back to exec_object. (Chris, Daniel) v4: Split pin flags into PIN_ZONE_4G and PIN_HIGH; update PIN_OFFSET_MASK to use last PIN_ defined instead of hard-coded value; use correct limit check in eb_vma_misplaced. (Chris) v5: Don't touch PIN_OFFSET_MASK and update workaround comment (Chris) v6: Apply pin-high for ggtt too (Chris) v7: Handle simultaneous pin-high and pin-mappable end correctly (Akash) Fix check for entries currently using +4GB addresses, use min_t and other polish in object_bind_to_vm (Chris) v8: Commit message updated to point to libdrm patch. v9: vmas are allocated in the correct ozone, so only check flag when the vma has not been allocated. (Chris) Cc: Chris Wilson Reviewed-by: Chris Wilson (v4) Signed-off-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 25 ++++++++++++++++------ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 11 ++++++++++ include/uapi/drm/i915_drm.h | 3 ++- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b17dac647787..1eab9bab152a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2819,6 +2819,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma); #define PIN_OFFSET_BIAS (1<<3) #define PIN_USER (1<<4) #define PIN_UPDATE (1<<5) +#define PIN_ZONE_4G (1<<6) +#define PIN_HIGH (1<<7) #define PIN_OFFSET_MASK (~4095) int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bf5ef7a07878..f0cfbb9ee12c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3354,11 +3354,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 fence_alignment, unfenced_alignment; + u32 search_flag, alloc_flag; + u64 start, end; u64 size, fence_size; - u64 start = - flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0; - u64 end = - flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total; struct i915_vma *vma; int ret; @@ -3398,6 +3396,13 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, size = flags & PIN_MAPPABLE ? fence_size : obj->base.size; } + start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0; + end = vm->total; + if (flags & PIN_MAPPABLE) + end = min_t(u64, end, dev_priv->gtt.mappable_end); + if (flags & PIN_ZONE_4G) + end = min_t(u64, end, (1ULL << 32)); + if (alignment == 0) alignment = flags & PIN_MAPPABLE ? fence_alignment : unfenced_alignment; @@ -3433,13 +3438,21 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, if (IS_ERR(vma)) goto err_unpin; + if (flags & PIN_HIGH) { + search_flag = DRM_MM_SEARCH_BELOW; + alloc_flag = DRM_MM_CREATE_TOP; + } else { + search_flag = DRM_MM_SEARCH_DEFAULT; + alloc_flag = DRM_MM_CREATE_DEFAULT; + } + search_free: ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, size, alignment, obj->cache_level, start, end, - DRM_MM_SEARCH_DEFAULT, - DRM_MM_CREATE_DEFAULT); + search_flag, + alloc_flag); if (ret) { ret = i915_gem_evict_something(dev, vm, size, alignment, obj->cache_level, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 67ef118ee160..edc17befc37d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -590,10 +590,17 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, flags |= PIN_GLOBAL; if (!drm_mm_node_allocated(&vma->node)) { + /* Wa32bitGeneralStateOffset & Wa32bitInstructionBaseOffset, + * limit address to the first 4GBs for unflagged objects. + */ + if ((entry->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) == 0) + flags |= PIN_ZONE_4G; if (entry->flags & __EXEC_OBJECT_NEEDS_MAP) flags |= PIN_GLOBAL | PIN_MAPPABLE; if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS; + if ((flags & PIN_MAPPABLE) == 0) + flags |= PIN_HIGH; } ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags); @@ -671,6 +678,10 @@ eb_vma_misplaced(struct i915_vma *vma) if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable) return !only_mappable_for_reloc(entry->flags); + if ((entry->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) == 0 && + (vma->node.start + vma->node.size - 1) >> 32) + return true; + return false; } diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index fd5aa47bd689..484a9fb20479 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -690,7 +690,8 @@ struct drm_i915_gem_exec_object2 { #define EXEC_OBJECT_NEEDS_FENCE (1<<0) #define EXEC_OBJECT_NEEDS_GTT (1<<1) #define EXEC_OBJECT_WRITE (1<<2) -#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_WRITE<<1) +#define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3) +#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_SUPPORTS_48B_ADDRESS<<1) __u64 flags; __u64 rsvd1; From f1d543485344f11f90e5fac637cc3430841ddabf Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 30 Sep 2015 23:00:42 +0300 Subject: [PATCH 081/134] drm/i915: remove duplicate names for the render ring INSTDONE register We use 3 different names to refer to the same render ring INSTDONE register. This can be confusing when comparing two parts of the code accessing the register via different names. Although the GEN4 version's layout is different, we treat it the same way as the GEN7+ version, in that we simply read it out during error capture. So remove the duplicates and leave a comment about the GEN4 difference. Note that there is also a GEN2 version of this register, but that's on a different address so not handled in this patch. Signed-off-by: Imre Deak Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 4 ++-- drivers/gpu/drm/i915/i915_reg.h | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d979dca1491a..27423ed98b60 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1390,10 +1390,10 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone) if (IS_GEN2(dev) || IS_GEN3(dev)) instdone[0] = I915_READ(INSTDONE); else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { - instdone[0] = I915_READ(INSTDONE_I965); + instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE)); instdone[1] = I915_READ(INSTDONE1); } else if (INTEL_INFO(dev)->gen >= 7) { - instdone[0] = I915_READ(GEN7_INSTDONE_1); + instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE)); instdone[1] = I915_READ(GEN7_SC_INSTDONE); instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE); instdone[3] = I915_READ(GEN7_ROW_INSTDONE); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9e3fdb372275..d1e3c3cd27cf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1593,14 +1593,16 @@ enum skl_disp_power_wells { #endif #define IPEIR_I965 0x02064 #define IPEHR_I965 0x02068 -#define INSTDONE_I965 0x0206c -#define GEN7_INSTDONE_1 0x0206c #define GEN7_SC_INSTDONE 0x07100 #define GEN7_SAMPLER_INSTDONE 0x0e160 #define GEN7_ROW_INSTDONE 0x0e164 #define I915_NUM_INSTDONE_REG 4 #define RING_IPEIR(base) ((base)+0x64) #define RING_IPEHR(base) ((base)+0x68) +/* + * On GEN4, only the render ring INSTDONE exists and has a different + * layout than the GEN7+ version. + */ #define RING_INSTDONE(base) ((base)+0x6c) #define RING_INSTPS(base) ((base)+0x70) #define RING_DMA_FADD(base) ((base)+0x78) From bd93a50e4dbae108a55a228bba1a69a2314096fb Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 30 Sep 2015 23:00:43 +0300 Subject: [PATCH 082/134] drm/i915: rename INSTDONE to GEN2_INSTDONE We have a bunch of INSTDONE registers for different platforms and purposes and it's not immediately clear which instance they are just by looking at the register name. This one was added on GEN2, where it was the only INSTDONE register, so mark it as such. Signed-off-by: Imre Deak Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 4 ++-- drivers/gpu/drm/i915/i915_reg.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 27423ed98b60..85d9a395376e 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -886,7 +886,7 @@ static void i915_record_ring_state(struct drm_device *dev, ering->faddr = I915_READ(DMA_FADD_I8XX); ering->ipeir = I915_READ(IPEIR); ering->ipehr = I915_READ(IPEHR); - ering->instdone = I915_READ(INSTDONE); + ering->instdone = I915_READ(GEN2_INSTDONE); } ering->waiting = waitqueue_active(&ring->irq_queue); @@ -1388,7 +1388,7 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone) memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG); if (IS_GEN2(dev) || IS_GEN3(dev)) - instdone[0] = I915_READ(INSTDONE); + instdone[0] = I915_READ(GEN2_INSTDONE); else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE)); instdone[1] = I915_READ(INSTDONE1); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d1e3c3cd27cf..5d2da1e6ea66 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1602,6 +1602,7 @@ enum skl_disp_power_wells { /* * On GEN4, only the render ring INSTDONE exists and has a different * layout than the GEN7+ version. + * The GEN2 counterpart of this register is GEN2_INSTDONE. */ #define RING_INSTDONE(base) ((base)+0x6c) #define RING_INSTPS(base) ((base)+0x70) @@ -1619,7 +1620,7 @@ enum skl_disp_power_wells { #define PWRCTX_EN (1<<0) #define IPEIR 0x02088 #define IPEHR 0x0208c -#define INSTDONE 0x02090 +#define GEN2_INSTDONE 0x02090 #define NOPID 0x02094 #define HWSTAM 0x02098 #define DMA_FADD_I8XX 0x020d0 From 13d70b8135e92274c9044d5ba4a543e1d6f0ef59 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 30 Sep 2015 23:00:44 +0300 Subject: [PATCH 083/134] drm/i915: rename INSTDONE1 to GEN4_INSTDONE1 This register was added on GEN4, by the name INSTDONE_1 whereas the GEN6 specification calls it INSTDONE_2. Keep the original name with a platform prefix to make it clearer which INSTDONE register instance this is. Also add a comment about the SNB alternative name. Signed-off-by: Imre Deak Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 85d9a395376e..2f04e4f2ff35 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1391,7 +1391,7 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone) instdone[0] = I915_READ(GEN2_INSTDONE); else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) { instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE)); - instdone[1] = I915_READ(INSTDONE1); + instdone[1] = I915_READ(GEN4_INSTDONE1); } else if (INTEL_INFO(dev)->gen >= 7) { instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE)); instdone[1] = I915_READ(GEN7_SC_INSTDONE); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5d2da1e6ea66..a1c313fbffb9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1611,7 +1611,7 @@ enum skl_disp_power_wells { #define RING_INSTPM(base) ((base)+0xc0) #define RING_MI_MODE(base) ((base)+0x9c) #define INSTPS 0x02070 /* 965+ only */ -#define INSTDONE1 0x0207c /* 965+ only */ +#define GEN4_INSTDONE1 0x0207c /* 965+ only, aka INSTDONE_2 on SNB */ #define ACTHD_I965 0x02074 #define HWS_PGA 0x02080 #define HWS_ADDRESS_MASK 0xfffff000 From 7d4aefd0a90dcced6ec24fd1908e4b407a8d4793 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Thu, 1 Oct 2015 22:23:49 +0530 Subject: [PATCH 084/134] drm/i915/bxt: DSI encoder support in CRTC modeset SKL and BXT qualifies the HAS_DDI() check, and hence haswell modeset functions are re-used for modeset sequence. But DDI interface doesn't include support for DSI. This patch adds: 1. cases for DSI encoder, in those modeset functions and allows a CRTC modeset 2. Adds call to pre_pll enabled from CRTC modeset function. Nothing needs to be done as such in CRTC for DSI encoder, as PLL, clock and and transcoder programming will be taken care in encoder's pre_enable and pre_pll_enable function. v2: Fixed Jani's review comments. Added INVALID_PORT for non DDI encoder like DSI for platforms having HAS_DDI as true. v3: Rebased on latest drm-nightly branch. Added a WARN_ON for invalid encoder. v4: WARN_ON for invalid encoder is refactored as per Jani's suggestion. Fixed the sequence for pre_pll_enable. v5: Protected DDI code paths in case of DSI encoder calls. Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 7 +++++-- drivers/gpu/drm/i915/intel_display.c | 21 +++++++++++++++------ drivers/gpu/drm/i915/intel_opregion.c | 9 +++++++-- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 2d3cc82dd8a4..b3f1748fab97 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -558,8 +558,10 @@ void intel_prepare_ddi(struct drm_device *dev) enum port port; bool supports_hdmi; - ddi_get_encoder_port(intel_encoder, &intel_dig_port, &port); + if (intel_encoder->type == INTEL_OUTPUT_DSI) + continue; + ddi_get_encoder_port(intel_encoder, &intel_dig_port, &port); if (visited[port]) continue; @@ -2043,7 +2045,8 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) { struct drm_crtc *crtc = &intel_crtc->base; - struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); enum port port = intel_ddi_get_encoder_port(intel_encoder); enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bbeb6d3aca1e..539c3737e823 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4965,6 +4965,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe, hsw_workaround_pipe; struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc->state); + bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI); if (WARN_ON(intel_crtc->active)) return; @@ -4994,9 +4995,12 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); - for_each_encoder_on_crtc(dev, crtc, encoder) + for_each_encoder_on_crtc(dev, crtc, encoder) { + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); if (encoder->pre_enable) encoder->pre_enable(encoder); + } if (intel_crtc->config->has_pch_encoder) { intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, @@ -5004,7 +5008,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) dev_priv->display.fdi_link_train(crtc); } - intel_ddi_enable_pipe_clock(intel_crtc); + if (!is_dsi) + intel_ddi_enable_pipe_clock(intel_crtc); if (INTEL_INFO(dev)->gen >= 9) skylake_pfit_enable(intel_crtc); @@ -5018,7 +5023,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); intel_ddi_set_pipe_settings(crtc); - intel_ddi_enable_transcoder_func(crtc); + if (!is_dsi) + intel_ddi_enable_transcoder_func(crtc); intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); @@ -5026,7 +5032,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) if (intel_crtc->config->has_pch_encoder) lpt_pch_enable(crtc); - if (intel_crtc->config->dp_encoder_is_mst) + if (intel_crtc->config->dp_encoder_is_mst && !is_dsi) intel_ddi_set_vc_payload_alloc(crtc, true); assert_vblank_disabled(crtc); @@ -5119,6 +5125,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; + bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI); for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); @@ -5136,14 +5143,16 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (intel_crtc->config->dp_encoder_is_mst) intel_ddi_set_vc_payload_alloc(crtc, false); - intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); + if (!is_dsi) + intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); if (INTEL_INFO(dev)->gen >= 9) skylake_scaler_disable(intel_crtc); else ironlake_pfit_disable(intel_crtc, false); - intel_ddi_disable_pipe_clock(intel_crtc); + if (!is_dsi) + intel_ddi_disable_pipe_clock(intel_crtc); if (intel_crtc->config->has_pch_encoder) { lpt_disable_pch_transcoder(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index cb1c65739425..b706b4e750da 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -341,8 +341,12 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, if (!HAS_DDI(dev)) return 0; - port = intel_ddi_get_encoder_port(intel_encoder); - if (port == PORT_E) { + if (intel_encoder->type == INTEL_OUTPUT_DSI) + port = 0; + else + port = intel_ddi_get_encoder_port(intel_encoder); + + if (port == PORT_E) { port = 0; } else { parm |= 1 << port; @@ -363,6 +367,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL; break; case INTEL_OUTPUT_EDP: + case INTEL_OUTPUT_DSI: type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL; break; default: From 37ab0810c9b7e06ec3904c186c46e9c540b3793b Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 1 Sep 2015 19:41:42 +0530 Subject: [PATCH 085/134] drm/i915/bxt: DSI enable for BXT This patch contains following changes: 1. MIPI device ready changes to support dsi_pre_enable. Changes are specific to BXT device ready sequence. Added check for ULPS mode(No effects on VLV). 2. Changes in dsi_enable to pick BXT port control register. 3. Changes in dsi_pre_enable to restrict DPIO programming for VLV v2: Fixed Jani's review comments. Removed the changes in VLV/CHV code. Fixed the macros to get proper port offsets. v3: Rebased on latest drm-nightly branch. Fixed Jani's review comments. Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 7 ++ drivers/gpu/drm/i915/intel_dsi.c | 165 +++++++++++++++++++++---------- 2 files changed, 119 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a1c313fbffb9..87de3a085ff6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7588,6 +7588,13 @@ enum skl_disp_power_wells { #define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) #define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) #define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL) + + /* BXT port control */ +#define _BXT_MIPIA_PORT_CTRL 0x6B0C0 +#define _BXT_MIPIC_PORT_CTRL 0x6B8C0 +#define BXT_MIPI_PORT_CTRL(tc) _MIPI_PORT(tc, _BXT_MIPIA_PORT_CTRL, \ + _BXT_MIPIC_PORT_CTRL) + #define DPI_ENABLE (1 << 31) /* A + C */ #define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 #define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index eb86ba7faaac..b7eae5248f47 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -282,58 +282,46 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, return true; } -static void intel_dsi_port_enable(struct intel_encoder *encoder) +static void bxt_dsi_device_ready(struct intel_encoder *encoder) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; - u32 temp; + u32 val; - if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { - temp = I915_READ(VLV_CHICKEN_3); - temp &= ~PIXEL_OVERLAP_CNT_MASK | - intel_dsi->pixel_overlap << - PIXEL_OVERLAP_CNT_SHIFT; - I915_WRITE(VLV_CHICKEN_3, temp); - } + DRM_DEBUG_KMS("\n"); + /* Exit Low power state in 4 steps*/ for_each_dsi_port(port, intel_dsi->ports) { - temp = I915_READ(MIPI_PORT_CTRL(port)); - temp &= ~LANE_CONFIGURATION_MASK; - temp &= ~DUAL_LINK_MODE_MASK; - if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) { - temp |= (intel_dsi->dual_link - 1) - << DUAL_LINK_MODE_SHIFT; - temp |= intel_crtc->pipe ? - LANE_CONFIGURATION_DUAL_LINK_B : - LANE_CONFIGURATION_DUAL_LINK_A; - } - /* assert ip_tg_enable signal */ - I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); + /* 1. Enable MIPI PHY transparent latch */ + val = I915_READ(BXT_MIPI_PORT_CTRL(port)); + I915_WRITE(BXT_MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD); + usleep_range(2000, 2500); + + /* 2. Enter ULPS */ + val = I915_READ(MIPI_DEVICE_READY(port)); + val &= ~ULPS_STATE_MASK; + val |= (ULPS_STATE_ENTER | DEVICE_READY); + I915_WRITE(MIPI_DEVICE_READY(port), val); + usleep_range(2, 3); + + /* 3. Exit ULPS */ + val = I915_READ(MIPI_DEVICE_READY(port)); + val &= ~ULPS_STATE_MASK; + val |= (ULPS_STATE_EXIT | DEVICE_READY); + I915_WRITE(MIPI_DEVICE_READY(port), val); + usleep_range(1000, 1500); + + /* Clear ULPS and set device ready */ + val = I915_READ(MIPI_DEVICE_READY(port)); + val &= ~ULPS_STATE_MASK; + val |= DEVICE_READY; + I915_WRITE(MIPI_DEVICE_READY(port), val); } } -static void intel_dsi_port_disable(struct intel_encoder *encoder) -{ - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); - enum port port; - u32 temp; - - for_each_dsi_port(port, intel_dsi->ports) { - /* de-assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); - } -} - -static void intel_dsi_device_ready(struct intel_encoder *encoder) +static void vlv_dsi_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); @@ -372,6 +360,72 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) } } +static void intel_dsi_device_ready(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + + if (IS_VALLEYVIEW(dev)) + vlv_dsi_device_ready(encoder); + else if (IS_BROXTON(dev)) + bxt_dsi_device_ready(encoder); +} + +static void intel_dsi_port_enable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 temp; + u32 port_ctrl; + + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { + temp = I915_READ(VLV_CHICKEN_3); + temp &= ~PIXEL_OVERLAP_CNT_MASK | + intel_dsi->pixel_overlap << + PIXEL_OVERLAP_CNT_SHIFT; + I915_WRITE(VLV_CHICKEN_3, temp); + } + + for_each_dsi_port(port, intel_dsi->ports) { + port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) : + MIPI_PORT_CTRL(port); + + temp = I915_READ(port_ctrl); + + temp &= ~LANE_CONFIGURATION_MASK; + temp &= ~DUAL_LINK_MODE_MASK; + + if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) { + temp |= (intel_dsi->dual_link - 1) + << DUAL_LINK_MODE_SHIFT; + temp |= intel_crtc->pipe ? + LANE_CONFIGURATION_DUAL_LINK_B : + LANE_CONFIGURATION_DUAL_LINK_A; + } + /* assert ip_tg_enable signal */ + I915_WRITE(port_ctrl, temp | DPI_ENABLE); + POSTING_READ(port_ctrl); + } +} + +static void intel_dsi_port_disable(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 temp; + + for_each_dsi_port(port, intel_dsi->ports) { + /* de-assert ip_tg_enable signal */ + temp = I915_READ(MIPI_PORT_CTRL(port)); + I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); + POSTING_READ(MIPI_PORT_CTRL(port)); + } +} + static void intel_dsi_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; @@ -419,19 +473,24 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) msleep(intel_dsi->panel_on_delay); - /* Disable DPOunit clock gating, can stall pipe - * and we need DPLL REFA always enabled */ - tmp = I915_READ(DPLL(pipe)); - tmp |= DPLL_REF_CLK_ENABLE_VLV; - I915_WRITE(DPLL(pipe), tmp); + if (IS_VALLEYVIEW(dev)) { + /* + * Disable DPOunit clock gating, can stall pipe + * and we need DPLL REFA always enabled + */ + tmp = I915_READ(DPLL(pipe)); + tmp |= DPLL_REF_CLK_ENABLE_VLV; + I915_WRITE(DPLL(pipe), tmp); - /* update the hw state for DPLL */ - intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV | - DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + /* update the hw state for DPLL */ + intel_crtc->config->dpll_hw_state.dpll = + DPLL_INTEGRATED_REF_CLK_VLV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; - tmp = I915_READ(DSPCLK_GATE_D); - tmp |= DPOUNIT_CLOCK_GATE_DISABLE; - I915_WRITE(DSPCLK_GATE_D, tmp); + tmp = I915_READ(DSPCLK_GATE_D); + tmp |= DPOUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, tmp); + } /* put device in ready state */ intel_dsi_device_ready(encoder); From 11b8e4f58e1baa94e44400a076b1a3757612ea55 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Wed, 23 Sep 2015 23:27:17 +0530 Subject: [PATCH 086/134] drm/i915/bxt: Program Tx Rx and Dphy clocks BXT DSI clocks are different than previous platforms. So adding a new function to program following clocks and dividers: 1. Program variable divider to generate input to Tx clock divider (Output value must be < 39.5Mhz) 2. Select divide by 2 option to get < 20Mhz for Tx clock 3. Program 8by3 divider to generate Rx clock v2: Fixed Jani's review comments. Adjusted the Macro definition as per convention. Simplified the logic for bit definitions for MIPI PORT A and PORT C in same registers. v3: Refactored the macros for TX, RX Escape and DPHY clocks as per Jani's suggestion. v4: Addressed Jani's review comments. Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 62 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dsi_pll.c | 42 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 87de3a085ff6..8c24851b930c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7547,6 +7547,68 @@ enum skl_disp_power_wells { #define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */ +/* BXT MIPI clock controls */ +#define BXT_MAX_VAR_OUTPUT_KHZ 39500 + +#define BXT_MIPI_CLOCK_CTL 0x46090 +#define BXT_MIPI1_DIV_SHIFT 26 +#define BXT_MIPI2_DIV_SHIFT 10 +#define BXT_MIPI_DIV_SHIFT(port) \ + _MIPI_PORT(port, BXT_MIPI1_DIV_SHIFT, \ + BXT_MIPI2_DIV_SHIFT) +/* Var clock divider to generate TX source. Result must be < 39.5 M */ +#define BXT_MIPI1_ESCLK_VAR_DIV_MASK (0x3F << 26) +#define BXT_MIPI2_ESCLK_VAR_DIV_MASK (0x3F << 10) +#define BXT_MIPI_ESCLK_VAR_DIV_MASK(port) \ + _MIPI_PORT(port, BXT_MIPI1_ESCLK_VAR_DIV_MASK, \ + BXT_MIPI2_ESCLK_VAR_DIV_MASK) + +#define BXT_MIPI_ESCLK_VAR_DIV(port, val) \ + (val << BXT_MIPI_DIV_SHIFT(port)) +/* TX control divider to select actual TX clock output from (8x/var) */ +#define BXT_MIPI1_TX_ESCLK_SHIFT 21 +#define BXT_MIPI2_TX_ESCLK_SHIFT 5 +#define BXT_MIPI_TX_ESCLK_SHIFT(port) \ + _MIPI_PORT(port, BXT_MIPI1_TX_ESCLK_SHIFT, \ + BXT_MIPI2_TX_ESCLK_SHIFT) +#define BXT_MIPI1_TX_ESCLK_FIXDIV_MASK (3 << 21) +#define BXT_MIPI2_TX_ESCLK_FIXDIV_MASK (3 << 5) +#define BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port) \ + _MIPI_PORT(port, BXT_MIPI1_TX_ESCLK_FIXDIV_MASK, \ + BXT_MIPI2_TX_ESCLK_FIXDIV_MASK) +#define BXT_MIPI_TX_ESCLK_8XDIV_BY2(port) \ + (0x0 << BXT_MIPI_TX_ESCLK_SHIFT(port)) +#define BXT_MIPI_TX_ESCLK_8XDIV_BY4(port) \ + (0x1 << BXT_MIPI_TX_ESCLK_SHIFT(port)) +#define BXT_MIPI_TX_ESCLK_8XDIV_BY8(port) \ + (0x2 << BXT_MIPI_TX_ESCLK_SHIFT(port)) +/* RX control divider to select actual RX clock output from 8x*/ +#define BXT_MIPI1_RX_ESCLK_SHIFT 19 +#define BXT_MIPI2_RX_ESCLK_SHIFT 3 +#define BXT_MIPI_RX_ESCLK_SHIFT(port) \ + _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_SHIFT, \ + BXT_MIPI2_RX_ESCLK_SHIFT) +#define BXT_MIPI1_RX_ESCLK_FIXDIV_MASK (3 << 19) +#define BXT_MIPI2_RX_ESCLK_FIXDIV_MASK (3 << 3) +#define BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port) \ + (3 << BXT_MIPI_RX_ESCLK_SHIFT(port)) +#define BXT_MIPI_RX_ESCLK_8X_BY2(port) \ + (1 << BXT_MIPI_RX_ESCLK_SHIFT(port)) +#define BXT_MIPI_RX_ESCLK_8X_BY3(port) \ + (2 << BXT_MIPI_RX_ESCLK_SHIFT(port)) +#define BXT_MIPI_RX_ESCLK_8X_BY4(port) \ + (3 << BXT_MIPI_RX_ESCLK_SHIFT(port)) +/* BXT-A WA: Always prog DPHY dividers to 00 */ +#define BXT_MIPI1_DPHY_DIV_SHIFT 16 +#define BXT_MIPI2_DPHY_DIV_SHIFT 0 +#define BXT_MIPI_DPHY_DIV_SHIFT(port) \ + _MIPI_PORT(port, BXT_MIPI1_DPHY_DIV_SHIFT, \ + BXT_MIPI2_DPHY_DIV_SHIFT) +#define BXT_MIPI_1_DPHY_DIVIDER_MASK (3 << 16) +#define BXT_MIPI_2_DPHY_DIVIDER_MASK (3 << 0) +#define BXT_MIPI_DPHY_DIVIDER_MASK(port) \ + (3 << BXT_MIPI_DPHY_DIV_SHIFT(port)) + /* BXT MIPI mode configure */ #define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8 #define _BXT_MIPIC_TRANS_HACTIVE 0x6B8F8 diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index f335e6cd4431..386336281997 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -384,6 +384,42 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) return pclk; } +/* Program BXT Mipi clocks and dividers */ +static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port) +{ + u32 tmp; + u32 divider; + u32 dsi_rate; + u32 pll_ratio; + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Clear old configurations */ + tmp = I915_READ(BXT_MIPI_CLOCK_CTL); + tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port)); + tmp &= ~(BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port)); + tmp &= ~(BXT_MIPI_ESCLK_VAR_DIV_MASK(port)); + tmp &= ~(BXT_MIPI_DPHY_DIVIDER_MASK(port)); + + /* Get the current DSI rate(actual) */ + pll_ratio = I915_READ(BXT_DSI_PLL_CTL) & + BXT_DSI_PLL_RATIO_MASK; + dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2; + + /* Max possible output of clock is 39.5 MHz, program value -1 */ + divider = (dsi_rate / BXT_MAX_VAR_OUTPUT_KHZ) - 1; + tmp |= BXT_MIPI_ESCLK_VAR_DIV(port, divider); + + /* + * Tx escape clock must be as close to 20MHz possible, but should + * not exceed it. Hence select divide by 2 + */ + tmp |= BXT_MIPI_TX_ESCLK_8XDIV_BY2(port); + + tmp |= BXT_MIPI_RX_ESCLK_8X_BY3(port); + + I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp); +} + static bool bxt_configure_dsi_pll(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -435,6 +471,8 @@ static bool bxt_configure_dsi_pll(struct intel_encoder *encoder) static void bxt_enable_dsi_pll(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; u32 val; DRM_DEBUG_KMS("\n"); @@ -453,6 +491,10 @@ static void bxt_enable_dsi_pll(struct intel_encoder *encoder) return; } + /* Program TX, RX, Dphy clocks */ + for_each_dsi_port(port, intel_dsi->ports) + bxt_dsi_program_clocks(encoder->base.dev, port); + /* Enable DSI PLL */ val = I915_READ(BXT_DSI_PLL_ENABLE); val |= BXT_DSI_PLL_DO_ENABLE; From b389a45c6b2f9b310ddf631d23b9e3e045cf747b Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 1 Sep 2015 19:41:44 +0530 Subject: [PATCH 087/134] drm/i915/bxt: DSI disable and post-disable This patch contains changes to support DSI disble sequence in BXT. The changes are: 1. BXT specific changes in clear_device_ready function. 2. BXT specific changes in DSI disable and post-disable functions. 3. Add a new function to reset BXT Dphy clock and dividers (bxt_dsi_reset_clocks). 4. Moved some part of the vlv clock reset code, in a new function (vlv_dsi_reset_clocks) maintaining the exact same sequence. 5. Wrapper function to call corresponding reset clock function. v2: Fixed Jani's review comments. v3: Removed the GET_DSI_PORT_CTRL Macro for consistency with earlier implementations as per Jani's suggestion. Signed-off-by: Uma Shankar Signed-off-by: Shashank Sharma Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 36 +++++++++++++------------ drivers/gpu/drm/i915/intel_dsi.h | 2 ++ drivers/gpu/drm/i915/intel_dsi_pll.c | 39 ++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b7eae5248f47..505501e808a2 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -417,12 +417,15 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; u32 temp; + u32 port_ctrl; for_each_dsi_port(port, intel_dsi->ports) { /* de-assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(port)); - I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); - POSTING_READ(MIPI_PORT_CTRL(port)); + port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) : + MIPI_PORT_CTRL(port); + temp = I915_READ(port_ctrl); + I915_WRITE(port_ctrl, temp & ~DPI_ENABLE); + POSTING_READ(port_ctrl); } } @@ -554,12 +557,7 @@ static void intel_dsi_disable(struct intel_encoder *encoder) /* Panel commands can be sent when clock is in LP11 */ I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - temp = I915_READ(MIPI_CTRL(port)); - temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; - I915_WRITE(MIPI_CTRL(port), temp | - intel_dsi->escape_clk_div << - ESCAPE_CLOCK_DIVIDER_SHIFT); - + intel_dsi_reset_clocks(encoder, port); I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); @@ -578,10 +576,12 @@ static void intel_dsi_disable(struct intel_encoder *encoder) static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { + struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; u32 val; + u32 port_ctrl = 0; DRM_DEBUG_KMS("\n"); for_each_dsi_port(port, intel_dsi->ports) { @@ -598,18 +598,22 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) ULPS_STATE_ENTER); usleep_range(2000, 2500); + if (IS_BROXTON(dev)) + port_ctrl = BXT_MIPI_PORT_CTRL(port); + else if (IS_VALLEYVIEW(dev)) + /* Common bit for both MIPI Port A & MIPI Port C */ + port_ctrl = MIPI_PORT_CTRL(PORT_A); + /* Wait till Clock lanes are in LP-00 state for MIPI Port A * only. MIPI Port C has no similar bit for checking */ - if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT) - == 0x00000), 30)) + if (wait_for(((I915_READ(port_ctrl) & AFE_LATCHOUT) + == 0x00000), 30)) DRM_ERROR("DSI LP not going Low\n"); - /* Disable MIPI PHY transparent latch - * Common bit for both MIPI Port A & MIPI Port C - */ - val = I915_READ(MIPI_PORT_CTRL(PORT_A)); - I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD); + /* Disable MIPI PHY transparent latch */ + val = I915_READ(port_ctrl); + I915_WRITE(port_ctrl, val & ~LP_OUTPUT_HOLD); usleep_range(1000, 1500); I915_WRITE(MIPI_DEVICE_READY(port), 0x00); diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 5cc46b4131f7..797a61245495 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -127,6 +127,8 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) extern void intel_enable_dsi_pll(struct intel_encoder *encoder); extern void intel_disable_dsi_pll(struct intel_encoder *encoder); extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp); +extern void intel_dsi_reset_clocks(struct intel_encoder *encoder, + enum port port); struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id); diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 386336281997..c9a38f4dec2d 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -384,6 +384,19 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) return pclk; } +void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) +{ + u32 temp; + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + + temp = I915_READ(MIPI_CTRL(port)); + temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; + I915_WRITE(MIPI_CTRL(port), temp | + intel_dsi->escape_clk_div << + ESCAPE_CLOCK_DIVIDER_SHIFT); +} + /* Program BXT Mipi clocks and dividers */ static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port) { @@ -528,3 +541,29 @@ void intel_disable_dsi_pll(struct intel_encoder *encoder) else if (IS_BROXTON(dev)) bxt_disable_dsi_pll(encoder); } + +void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) +{ + u32 tmp; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Clear old configurations */ + tmp = I915_READ(BXT_MIPI_CLOCK_CTL); + tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port)); + tmp &= ~(BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port)); + tmp &= ~(BXT_MIPI_ESCLK_VAR_DIV_MASK(port)); + tmp &= ~(BXT_MIPI_DPHY_DIVIDER_MASK(port)); + I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp); + I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); +} + +void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) +{ + struct drm_device *dev = encoder->base.dev; + + if (IS_BROXTON(dev)) + bxt_dsi_reset_clocks(encoder, port); + else if (IS_VALLEYVIEW(dev)) + vlv_dsi_reset_clocks(encoder, port); +} From baeac68a82f07f7c37bfc3d9624127b813a8d8b4 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 1 Sep 2015 19:41:45 +0530 Subject: [PATCH 088/134] drm/i915/bxt: get_hw_state for BXT Pick appropriate port control register (BXT or VLV), based on device. Get the current hw state wrt Mipi port. v2: Rebased on latest drm nightly branch. v3: Removed the GET_DSI_PORT_CTRL Macro for consistency with earlier implementations as per Jani's suggestion. Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 505501e808a2..65911065e654 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -656,7 +656,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct drm_device *dev = encoder->base.dev; enum intel_display_power_domain power_domain; - u32 dpi_enabled, func; + u32 dpi_enabled, func, ctrl_reg; enum port port; DRM_DEBUG_KMS("\n"); @@ -668,8 +668,9 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, /* XXX: this only works for one DSI output */ for_each_dsi_port(port, intel_dsi->ports) { func = I915_READ(MIPI_DSI_FUNC_PRG(port)); - dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) & - DPI_ENABLE; + ctrl_reg = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) : + MIPI_PORT_CTRL(port); + dpi_enabled = I915_READ(ctrl_reg) & DPI_ENABLE; /* Due to some hardware limitations on BYT, MIPI Port C DPI * Enable bit does not get set. To check whether DSI Port C From ce0c982152137789e6f09e9d8712034088adf3aa Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 1 Sep 2015 19:41:46 +0530 Subject: [PATCH 089/134] drm/i915/bxt: get DSI pixelclock BXT's DSI PLL is different from that of VLV. So this patch adds a new function to get the current DSI pixel clock based on the PLL divider ratio and lane count. This function is required for intel_dsi_get_config() function. v2: Fixed Jani's review comments. Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 8 +++++-- drivers/gpu/drm/i915/intel_dsi.h | 1 + drivers/gpu/drm/i915/intel_dsi_pll.c | 35 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 65911065e654..170ae6f4866e 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -695,7 +695,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, static void intel_dsi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { - u32 pclk; + u32 pclk = 0; DRM_DEBUG_KMS("\n"); /* @@ -704,7 +704,11 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, */ pipe_config->dpll_hw_state.dpll_md = 0; - pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp); + if (IS_BROXTON(encoder->base.dev)) + pclk = bxt_get_dsi_pclk(encoder, pipe_config->pipe_bpp); + else if (IS_VALLEYVIEW(encoder->base.dev)) + pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp); + if (!pclk) return; diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 797a61245495..e6cb25239941 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -127,6 +127,7 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) extern void intel_enable_dsi_pll(struct intel_encoder *encoder); extern void intel_disable_dsi_pll(struct intel_encoder *encoder); extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp); +extern u32 bxt_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp); extern void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port); diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index c9a38f4dec2d..22c1ea9d3748 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -384,6 +384,41 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) return pclk; } +u32 bxt_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) +{ + u32 pclk; + u32 dsi_clk; + u32 dsi_ratio; + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + + /* Divide by zero */ + if (!pipe_bpp) { + DRM_ERROR("Invalid BPP(0)\n"); + return 0; + } + + dsi_ratio = I915_READ(BXT_DSI_PLL_CTL) & + BXT_DSI_PLL_RATIO_MASK; + + /* Invalid DSI ratio ? */ + if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN || + dsi_ratio > BXT_DSI_PLL_RATIO_MAX) { + DRM_ERROR("Invalid DSI pll ratio(%u) programmed\n", dsi_ratio); + return 0; + } + + dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2; + + /* pixel_format and pipe_bpp should agree */ + assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp); + + pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, pipe_bpp); + + DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk); + return pclk; +} + void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) { u32 temp; From 022e4e52a750066047b22031733df70e136ae299 Mon Sep 17 00:00:00 2001 From: Sunil Kamath Date: Wed, 30 Sep 2015 22:34:57 +0530 Subject: [PATCH 090/134] drm/i915/bxt: Modify BXT BLC according to VBT changes Latest VBT mentions which set of registers will be used for BLC, as controller number field. Making use of this field in BXT BLC implementation. Also, the registers are used in case control pin indicates display DDI. Adding a check for this. According to Bspec, BLC_PWM_*_2 uses the display utility pin for output. To use backlight 2, enable the utility pin with mode = PWM v2: Jani's review comments addressed - Add a prefix _ to BXT BLC registers definitions. - Add "bxt only" comment for u8 controller - Remove control_pin check for DDI controller - Check for valid controller values - Set pipe bits in UTIL_PIN_CTL - Enable/Disable UTIL_PIN_CTL in enable/disable_backlight() - If BLC 2 is used, read active_low_pwm from UTIL_PIN polarity Satheesh's review comment addressed - If UTIL PIN is already enabled, BIOS would have programmed it. No need to disable and enable again. v3: Jani's review comments - add UTIL_PIN_PIPE_MASK and UTIL_PIN_MODE_MASK - Disable UTIL_PIN if controller 1 is used - Mask out UTIL_PIN_PIPE_MASK and UTIL_PIN_MODE_MASK before enabling UTIL_PIN - check valid controller value in intel_bios.c - add backlight.util_pin_active_low - disable util pin before enabling v4: Change for BXT-PO branch: Stubbed unwanted definition which was existing before because of DC6 patch. UTIL_PIN_MODE_PWM (0x1b << 24) v2: Fixed Jani's review comment. v3: Split the backight PWM frequency programming into separate patch, in cases BIOS doesn't initializes it. v4: Starting afresh and not modifying existing state for backlight, as per Jani's recommendation. v5: Fixed Jani's review comment wrt util pin enable Signed-off-by: Vandana Kannan Signed-off-by: Sunil Kamath Signed-off-by: Uma Shankar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 24 ++++++--- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_panel.c | 81 ++++++++++++++++++++++++------ 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8c24851b930c..8d7be66d96bc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3627,17 +3627,29 @@ enum skl_disp_power_wells { #define UTIL_PIN_CTL 0x48400 #define UTIL_PIN_ENABLE (1 << 31) +#define UTIL_PIN_PIPE(x) ((x) << 29) +#define UTIL_PIN_PIPE_MASK (3 << 29) +#define UTIL_PIN_MODE_PWM (1 << 24) +#define UTIL_PIN_MODE_MASK (0xf << 24) +#define UTIL_PIN_POLARITY (1 << 22) + /* BXT backlight register definition. */ -#define BXT_BLC_PWM_CTL1 0xC8250 +#define _BXT_BLC_PWM_CTL1 0xC8250 #define BXT_BLC_PWM_ENABLE (1 << 31) #define BXT_BLC_PWM_POLARITY (1 << 29) -#define BXT_BLC_PWM_FREQ1 0xC8254 -#define BXT_BLC_PWM_DUTY1 0xC8258 +#define _BXT_BLC_PWM_FREQ1 0xC8254 +#define _BXT_BLC_PWM_DUTY1 0xC8258 -#define BXT_BLC_PWM_CTL2 0xC8350 -#define BXT_BLC_PWM_FREQ2 0xC8354 -#define BXT_BLC_PWM_DUTY2 0xC8358 +#define _BXT_BLC_PWM_CTL2 0xC8350 +#define _BXT_BLC_PWM_FREQ2 0xC8354 +#define _BXT_BLC_PWM_DUTY2 0xC8358 +#define BXT_BLC_PWM_CTL(controller) _PIPE(controller, \ + _BXT_BLC_PWM_CTL1, _BXT_BLC_PWM_CTL2) +#define BXT_BLC_PWM_FREQ(controller) _PIPE(controller, \ + _BXT_BLC_PWM_FREQ1, _BXT_BLC_PWM_FREQ2) +#define BXT_BLC_PWM_DUTY(controller) _PIPE(controller, \ + _BXT_BLC_PWM_DUTY1, _BXT_BLC_PWM_DUTY2) #define PCH_GTC_CTL 0xe7000 #define PCH_GTC_ENABLE (1 << 31) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index dfd2d10d3d3c..563c4f1e3685 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -179,6 +179,8 @@ struct intel_panel { bool active_low_pwm; /* PWM chip */ + bool util_pin_active_low; /* bxt+ */ + u8 controller; /* bxt+ only */ struct pwm_device *pwm; struct backlight_device *device; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 4d28c7b904e7..f30c996e882c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -536,9 +536,10 @@ static u32 vlv_get_backlight(struct intel_connector *connector) static u32 bxt_get_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; + struct intel_panel *panel = &connector->panel; struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(BXT_BLC_PWM_DUTY1); + return I915_READ(BXT_BLC_PWM_DUTY(panel->backlight.controller)); } static u32 pwm_get_backlight(struct intel_connector *connector) @@ -634,8 +635,9 @@ static void bxt_set_backlight(struct intel_connector *connector, u32 level) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; - I915_WRITE(BXT_BLC_PWM_DUTY1, level); + I915_WRITE(BXT_BLC_PWM_DUTY(panel->backlight.controller), level); } static void pwm_set_backlight(struct intel_connector *connector, u32 level) @@ -786,12 +788,20 @@ static void bxt_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 tmp; + struct intel_panel *panel = &connector->panel; + u32 tmp, val; intel_panel_actually_set_backlight(connector, 0); - tmp = I915_READ(BXT_BLC_PWM_CTL1); - I915_WRITE(BXT_BLC_PWM_CTL1, tmp & ~BXT_BLC_PWM_ENABLE); + tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); + I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), + tmp & ~BXT_BLC_PWM_ENABLE); + + if (panel->backlight.controller == 1) { + val = I915_READ(UTIL_PIN_CTL); + val &= ~UTIL_PIN_ENABLE; + I915_WRITE(UTIL_PIN_CTL, val); + } } static void pwm_disable_backlight(struct intel_connector *connector) @@ -1023,16 +1033,38 @@ static void bxt_enable_backlight(struct intel_connector *connector) struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; - u32 pwm_ctl; + enum pipe pipe = intel_get_pipe_from_connector(connector); + u32 pwm_ctl, val; - pwm_ctl = I915_READ(BXT_BLC_PWM_CTL1); + /* To use 2nd set of backlight registers, utility pin has to be + * enabled with PWM mode. + * The field should only be changed when the utility pin is disabled + */ + if (panel->backlight.controller == 1) { + val = I915_READ(UTIL_PIN_CTL); + if (val & UTIL_PIN_ENABLE) { + DRM_DEBUG_KMS("util pin already enabled\n"); + val &= ~UTIL_PIN_ENABLE; + I915_WRITE(UTIL_PIN_CTL, val); + } + + val = 0; + if (panel->backlight.util_pin_active_low) + val |= UTIL_PIN_POLARITY; + I915_WRITE(UTIL_PIN_CTL, val | UTIL_PIN_PIPE(pipe) | + UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE); + } + + pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); if (pwm_ctl & BXT_BLC_PWM_ENABLE) { DRM_DEBUG_KMS("backlight already enabled\n"); pwm_ctl &= ~BXT_BLC_PWM_ENABLE; - I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl); + I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl); } - I915_WRITE(BXT_BLC_PWM_FREQ1, panel->backlight.max); + I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller), + panel->backlight.max); intel_panel_actually_set_backlight(connector, panel->backlight.level); @@ -1040,9 +1072,10 @@ static void bxt_enable_backlight(struct intel_connector *connector) if (panel->backlight.active_low_pwm) pwm_ctl |= BXT_BLC_PWM_POLARITY; - I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl); - POSTING_READ(BXT_BLC_PWM_CTL1); - I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl | BXT_BLC_PWM_ENABLE); + I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl); + POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); + I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), + pwm_ctl | BXT_BLC_PWM_ENABLE); } static void pwm_enable_backlight(struct intel_connector *connector) @@ -1562,10 +1595,28 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) struct intel_panel *panel = &connector->panel; u32 pwm_ctl, val; - pwm_ctl = I915_READ(BXT_BLC_PWM_CTL1); - panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; + /* + * For BXT hard coding the Backlight controller to 0. + * TODO : Read the controller value from VBT and generalize + */ + panel->backlight.controller = 0; - panel->backlight.max = I915_READ(BXT_BLC_PWM_FREQ1); + pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); + + /* Keeping the check if controller 1 is to be programmed. + * This will come into affect once the VBT parsing + * is fixed for controller selection, and controller 1 is used + * for a prticular display configuration. + */ + if (panel->backlight.controller == 1) { + val = I915_READ(UTIL_PIN_CTL); + panel->backlight.util_pin_active_low = + val & UTIL_PIN_POLARITY; + } + + panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; + panel->backlight.max = + I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller)); if (!panel->backlight.max) panel->backlight.max = get_backlight_max_vbt(connector); From 068127601eefa0565f4b2f4d82750cad9e37000c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 2 Oct 2015 18:14:22 +0300 Subject: [PATCH 091/134] drm/i915: unlock on error in i915_ppgtt_info() We need to call intel_runtime_pm_put() and mutex_unlock() before returning. Fixes: 7cb5dff8d59d ('drm/i915: fix task reference leak in i915_debugfs.c') Signed-off-by: Dan Carpenter Acked-by: Geliang Tang Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 77ee8c5062b9..7e65015ecbee 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2298,18 +2298,21 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) struct task_struct *task; task = get_pid_task(file->pid, PIDTYPE_PID); - if (!task) - return -ESRCH; + if (!task) { + ret = -ESRCH; + goto out_put; + } seq_printf(m, "\nproc: %s\n", task->comm); put_task_struct(task); idr_for_each(&file_priv->context_idr, per_file_ctx, (void *)(unsigned long)m); } +out_put: intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } static int count_irq_waiters(struct drm_i915_private *i915) From 5d250b05918c002b63632c7db91c3c5f924c6a3b Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Mon, 5 Oct 2015 16:43:14 +0530 Subject: [PATCH 092/134] drm/i915: Call encoder hotplug for init and resume cases For all the encoders, call the hot_plug if it is registered. This is required for connected boot and resume cases to generate fake hpd resulting in reading of edid. Removing the initial sdvo hot_plug call too so that it will be called just once from this loop. Signed-off-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hotplug.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_sdvo.c | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 53c0173a39fe..eac47571e409 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -458,6 +458,7 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; struct drm_connector *connector; int i; @@ -482,6 +483,16 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); spin_unlock_irq(&dev_priv->irq_lock); + + /* + * Connected boot / resume scenarios can't generate new hot plug. + * So, probe it manually. + */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->hot_plug) + encoder->hot_plug(encoder); + } } void intel_hpd_init_work(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index c42b636c2087..853f4b2f50db 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2460,7 +2460,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) * Ensure that they get re-enabled when an interrupt happens. */ intel_encoder->hot_plug = intel_sdvo_enable_hotplug; - intel_sdvo_enable_hotplug(intel_encoder); } else { intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; } From 9571b190cf474ae02a7e018a21d14052d750070f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 18:05:44 +0300 Subject: [PATCH 093/134] drm/i915: Don't bypass LRC on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs are unclear as usual, so it's not clear whether LRC should be bypassed, performed normally or GRC code should be used as the LRC code. Some old docs stated that LRC bypass ought to be used, more recent ones no longer say that. Some docs indicated that we could use GRC as the LRC code on CHV, but the BIOS doesn't do that, so let's not do it either. Besides to enable LRC bypass properly, I believe we should set the bit already before deasserting cmnreset. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 ----- drivers/gpu/drm/i915/intel_hdmi.c | 5 ----- 2 files changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 97ed418060ff..19cbc2ef542c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3417,11 +3417,6 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); } - /* LRC Bypass */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); - val |= DPIO_LRC_BYPASS; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val); - mutex_unlock(&dev_priv->sb_lock); return 0; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 3c5f2c922180..3b28ed3237d3 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1952,11 +1952,6 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); - /* LRC Bypass */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); - val |= DPIO_LRC_BYPASS; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val); - mutex_unlock(&dev_priv->sb_lock); intel_hdmi->set_infoframes(&encoder->base, From 3be60de9e9dc92c852c196cf4b62e287fa53963c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 18:05:45 +0300 Subject: [PATCH 094/134] drm/i915: Skip CHV PHY asserts until PHY has been fully reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BIOS can leave the CHV display PHY in some odd state where some of the LDOs/lanes won't power down fully when unused. This will trigger a host of asserts that were added in: 30142273a3e83936fd7b45aa5339311a9295ca51 drm/i915: Add CHV PHY LDO power sanity checks 6669e39f95b5530ca8cb9137703ceb5e83e5d648 drm/i915: Add some CHV DPIO lane power state asserts To avoid that, skip the asserts until the PHY power well has been disabled at least once. That will fully reset the PHY, and once brought back up, the dynamic power down features will work correctly. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/intel_runtime_pm.c | 46 ++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1eab9bab152a..35bf5cb04785 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1953,6 +1953,9 @@ struct drm_i915_private { bool edp_low_vswing; + /* perform PHY state sanity checks? */ + bool chv_phy_assert[2]; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index e1fdbabaf2bf..0cfe4c14866a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -993,8 +993,29 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D); u32 phy_control = dev_priv->chv_phy_control; u32 phy_status = 0; + u32 phy_status_mask = 0xffffffff; u32 tmp; + /* + * The BIOS can leave the PHY is some weird state + * where it doesn't fully power down some parts. + * Disable the asserts until the PHY has been fully + * reset (ie. the power well has been disabled at + * least once). + */ + if (!dev_priv->chv_phy_assert[DPIO_PHY0]) + phy_status_mask &= ~(PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 1) | + PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH1) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1)); + + if (!dev_priv->chv_phy_assert[DPIO_PHY1]) + phy_status_mask &= ~(PHY_STATUS_CMN_LDO(DPIO_PHY1, DPIO_CH0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1)); + if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) { phy_status |= PHY_POWERGOOD(DPIO_PHY0); @@ -1055,11 +1076,13 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1); } + phy_status &= phy_status_mask; + /* * The PHY may be busy with some initial calibration and whatnot, * so the power state can take a while to actually change. */ - if (wait_for((tmp = I915_READ(DISPLAY_PHY_STATUS)) == phy_status, 10)) + if (wait_for((tmp = I915_READ(DISPLAY_PHY_STATUS) & phy_status_mask) == phy_status, 10)) WARN(phy_status != tmp, "Unexpected PHY_STATUS 0x%08x, expected 0x%08x (PHY_CONTROL=0x%08x)\n", tmp, phy_status, dev_priv->chv_phy_control); @@ -1152,6 +1175,9 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Disabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n", phy, dev_priv->chv_phy_control); + /* PHY is fully reset now, so we can enable the PHY state asserts */ + dev_priv->chv_phy_assert[phy] = true; + assert_chv_phy_status(dev_priv); } @@ -1161,6 +1187,16 @@ static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpi enum pipe pipe = phy == DPIO_PHY0 ? PIPE_A : PIPE_C; u32 reg, val, expected, actual; + /* + * The BIOS can leave the PHY is some weird state + * where it doesn't fully power down some parts. + * Disable the asserts until the PHY has been fully + * reset (ie. the power well has been disabled at + * least once). + */ + if (!dev_priv->chv_phy_assert[phy]) + return; + if (ch == DPIO_CH0) reg = _CHV_CMN_DW0_CH0; else @@ -1916,6 +1952,10 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH1); dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY0); + + dev_priv->chv_phy_assert[DPIO_PHY0] = false; + } else { + dev_priv->chv_phy_assert[DPIO_PHY0] = true; } if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { @@ -1934,6 +1974,10 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY1, DPIO_CH0); dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY1); + + dev_priv->chv_phy_assert[DPIO_PHY1] = false; + } else { + dev_priv->chv_phy_assert[DPIO_PHY1] = true; } I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); From a1c4199414539d7eea34e416fb64fb5178221381 Mon Sep 17 00:00:00 2001 From: Alex Dai Date: Wed, 30 Sep 2015 09:46:37 -0700 Subject: [PATCH 095/134] drm/i915/guc: Add host2guc notification for suspend and resume Add host2guc interface to notify GuC power state changes when enter or resume from power saving state. v3: Move intel_guc_suspend to i915_drm_suspend for consistency. v2: Add GuC suspend/resume to runtime suspend/resume too v1: Change to a more flexible way when fill host to GuC scratch data in order to remove hard coding. Signed-off-by: Alex Dai Reviewed-by: Sagar Arun Kamble Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 8 ++++ drivers/gpu/drm/i915/i915_guc_submission.c | 50 ++++++++++++++++++++++ drivers/gpu/drm/i915/intel_guc.h | 2 + drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++ drivers/gpu/drm/i915/intel_guc_loader.c | 4 +- 5 files changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1cb6b82e17d4..760e0ce4aa26 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -638,6 +638,8 @@ static int i915_drm_suspend(struct drm_device *dev) return error; } + intel_guc_suspend(dev); + intel_suspend_gt_powersave(dev); /* @@ -767,6 +769,8 @@ static int i915_drm_resume(struct drm_device *dev) } mutex_unlock(&dev->struct_mutex); + intel_guc_resume(dev); + intel_modeset_init_hw(dev); spin_lock_irq(&dev_priv->irq_lock); @@ -1500,6 +1504,8 @@ static int intel_runtime_suspend(struct device *device) i915_gem_release_all_mmaps(dev_priv); mutex_unlock(&dev->struct_mutex); + intel_guc_suspend(dev); + intel_suspend_gt_powersave(dev); intel_runtime_pm_disable_interrupts(dev_priv); @@ -1559,6 +1565,8 @@ static int intel_runtime_resume(struct device *device) intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; + intel_guc_resume(dev); + if (IS_GEN6(dev_priv)) intel_init_pch_refclk(dev); diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 0b1797f52aaf..036b42bae827 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -923,3 +923,53 @@ void i915_guc_submission_fini(struct drm_device *dev) gem_release_guc_obj(guc->ctx_pool_obj); guc->ctx_pool_obj = NULL; } + +/** + * intel_guc_suspend() - notify GuC entering suspend state + * @dev: drm device + */ +int intel_guc_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_guc *guc = &dev_priv->guc; + struct intel_context *ctx; + u32 data[3]; + + if (!i915.enable_guc_submission) + return 0; + + ctx = dev_priv->ring[RCS].default_context; + + data[0] = HOST2GUC_ACTION_ENTER_S_STATE; + /* any value greater than GUC_POWER_D0 */ + data[1] = GUC_POWER_D1; + /* first page is shared data with GuC */ + data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state); + + return host2guc_action(guc, data, ARRAY_SIZE(data)); +} + + +/** + * intel_guc_resume() - notify GuC resuming from suspend state + * @dev: drm device + */ +int intel_guc_resume(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_guc *guc = &dev_priv->guc; + struct intel_context *ctx; + u32 data[3]; + + if (!i915.enable_guc_submission) + return 0; + + ctx = dev_priv->ring[RCS].default_context; + + data[0] = HOST2GUC_ACTION_EXIT_S_STATE; + data[1] = GUC_POWER_D0; + /* first page is shared data with GuC */ + data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state); + + return host2guc_action(guc, data, ARRAY_SIZE(data)); +} diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 4ec2d27a557e..081d5f648d26 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -110,6 +110,8 @@ extern void intel_guc_ucode_init(struct drm_device *dev); extern int intel_guc_ucode_load(struct drm_device *dev); extern void intel_guc_ucode_fini(struct drm_device *dev); extern const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status); +extern int intel_guc_suspend(struct drm_device *dev); +extern int intel_guc_resume(struct drm_device *dev); /* i915_guc_submission.c */ int i915_guc_submission_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 6c78fdf685e2..593d2f585978 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -221,12 +221,20 @@ struct guc_context_desc { #define GUC_FORCEWAKE_RENDER (1 << 0) #define GUC_FORCEWAKE_MEDIA (1 << 1) +#define GUC_POWER_UNSPECIFIED 0 +#define GUC_POWER_D0 1 +#define GUC_POWER_D1 2 +#define GUC_POWER_D2 3 +#define GUC_POWER_D3 4 + /* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */ enum host2guc_action { HOST2GUC_ACTION_DEFAULT = 0x0, HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6, HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10, HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20, + HOST2GUC_ACTION_ENTER_S_STATE = 0x501, + HOST2GUC_ACTION_EXIT_S_STATE = 0x502, HOST2GUC_ACTION_SLPC_REQUEST = 0x3003, HOST2GUC_ACTION_LIMIT }; diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index f87d833aa5ca..a17b6a56be83 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -383,7 +383,6 @@ int intel_guc_ucode_load(struct drm_device *dev) intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); direct_interrupts_to_host(dev_priv); - i915_guc_submission_disable(dev); if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_NONE) return 0; @@ -433,6 +432,9 @@ int intel_guc_ucode_load(struct drm_device *dev) intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); if (i915.enable_guc_submission) { + /* The execbuf_client will be recreated. Release it first. */ + i915_guc_submission_disable(dev); + err = i915_guc_submission_enable(dev); if (err) goto fail; From 3e7732a05d3b14e2ae33013622ae9c691b419312 Mon Sep 17 00:00:00 2001 From: Sagar Arun Kamble Date: Thu, 1 Oct 2015 20:29:27 +0530 Subject: [PATCH 096/134] drm/i915: Update Promotion timer for RC6 TO Mode When using RC6 timeout mode, the timeout value should be written to GEN6_RC6_THRESHOLD. v2: Updated commit message. (Tom) v3: Rebase over whitespace differences. (Daniel) Cc: Tom O'Rourke Signed-off-by: Sagar Arun Kamble Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index eb9a66d3a477..60d120c472ab 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4730,7 +4730,6 @@ static void gen9_enable_rc6(struct drm_device *dev) I915_WRITE(GUC_MAX_IDLE_COUNT, 0xA); I915_WRITE(GEN6_RC_SLEEP, 0); - I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */ /* 2c: Program Coarse Power Gating Policies. */ I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 25); @@ -4741,16 +4740,19 @@ static void gen9_enable_rc6(struct drm_device *dev) rc6_mask = GEN6_RC_CTL_RC6_ENABLE; DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off"); - + /* WaRsUseTimeoutMode */ if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) + (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) { + I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */ I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | GEN7_RC_CTL_TO_MODE | rc6_mask); - else + } else { + I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */ I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | GEN6_RC_CTL_EI_MODE(1) | rc6_mask); + } /* * 3b: Enable Coarse Power Gating only when RC6 is enabled. From 7b9748cb513a6bef4af87b79f0da3ff7e8b56cd8 Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Thu, 1 Oct 2015 23:09:58 -0700 Subject: [PATCH 097/134] drm/i915: Add GEN7_GPGPU_DISPATCHDIMX/Y/Z to the register whitelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required to support glDispatchComputeIndirect for gen7. Signed-off-by: Jordan Justen Reviewed-by: Kristian Høgsberg Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 6 +++++- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 09932cab1a3f..db58c8d664c2 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -448,6 +448,9 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG32(GEN7_3DPRIM_INSTANCE_COUNT), REG32(GEN7_3DPRIM_START_INSTANCE), REG32(GEN7_3DPRIM_BASE_VERTEX), + REG32(GEN7_GPGPU_DISPATCHDIMX), + REG32(GEN7_GPGPU_DISPATCHDIMY), + REG32(GEN7_GPGPU_DISPATCHDIMZ), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), @@ -1214,6 +1217,7 @@ int i915_cmd_parser_get_version(void) * MI_PREDICATE_SRC1 registers. * 3. Allow access to the GPGPU_THREADS_DISPATCHED register. * 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3. + * 5. GPGPU dispatch compute indirect registers. */ - return 4; + return 5; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8d7be66d96bc..07588b63d434 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -536,6 +536,10 @@ #define GEN7_3DPRIM_START_INSTANCE 0x243C #define GEN7_3DPRIM_BASE_VERTEX 0x2440 +#define GEN7_GPGPU_DISPATCHDIMX 0x2500 +#define GEN7_GPGPU_DISPATCHDIMY 0x2504 +#define GEN7_GPGPU_DISPATCHDIMZ 0x2508 + #define OACONTROL 0x2360 #define _GEN7_PIPEA_DE_LOAD_SL 0x70068 From 0b5e88dc25ee6c9040c0355e6e025dcbc9c8de92 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Mon, 5 Oct 2015 16:43:15 +0530 Subject: [PATCH 098/134] drm/i915: Add hot_plug hook for hdmi encoder This patch adds a separate probe function for HDMI EDID read over DDC channel. This function has been registered as a .hot_plug handler for HDMI encoder. The current implementation of hdmi_detect() function re-sets the cached HDMI edid (in connector->detect_edid) in every detect call.This function gets called many times, sometimes directly from userspace probes, forcing drivers to read EDID every detect function call.This causes several problems like: 1. Race conditions in multiple hot_plug / unplug cases, between interrupts bottom halves and userspace detections. 2. Many Un-necessary EDID reads for single hotplug/unplug 3. HDMI complaince failures which expects only one EDID read per hotplug This function will be serving the purpose of really reading the EDID by really probing the DDC channel, and updating the cached EDID. The plan is to: 1. i915 IRQ handler bottom half function already calls intel_encoder->hotplug() function. Adding This probe function which will read the EDID only in case of a hotplug / unplug. 2. During init_connector this probe will be called to read the edid 3. Reuse the cached EDID in hdmi_detect() function. The "< gen7" check is there because this was tested only for >=gen7 platforms. For older platforms the hotplug/reading edid path remains same. v2: Calling set_edid instead of hdmi_probe during init. Also, for platforms having DDI, intel_encoder for DP and HDMI is same (taken from intel_dig_port), so for DP also, hot_plug function gets called which is not intended here. So, check for HDMI in intel_hdmi_probe Rely on HPD for updating edid only for platforms gen > 8 and also for VLV. v3: Dropping the gen < 8 || !VLV check. Now all platforms should rely on hotplug or init for updating the edid.(Daniel) Also, calling hdmi_probe in init instead of set_edid v4: Renaming intel_hdmi_probe to intel_hdmi_hot_plug. Also calling this hotplug handler from intel_hpd_init to take care of init resume scenarios. v5: Moved the call to encoder hotplug during init to separate patch(Daniel) Signed-off-by: Shashank Sharma Signed-off-by: Sonika Jindal [danvet: Mark intel_hdmi_hot_plug as static.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 54 ++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 3b28ed3237d3..03d85909c6ab 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1369,18 +1369,16 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force) return connected; } -static enum drm_connector_status -intel_hdmi_detect(struct drm_connector *connector, bool force) +static void intel_hdmi_hot_plug(struct intel_encoder *intel_encoder) { - enum drm_connector_status status; - struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); - struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct intel_hdmi *intel_hdmi = + enc_to_intel_hdmi(&intel_encoder->base); + struct intel_connector *intel_connector = + intel_hdmi->attached_connector; + struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); bool live_status = false; unsigned int retry = 3; - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", - connector->base.id, connector->name); - while (!live_status && --retry) { live_status = intel_digital_port_connected(dev_priv, hdmi_to_dig_port(intel_hdmi)); @@ -1390,15 +1388,48 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) if (!live_status) DRM_DEBUG_KMS("Live status not up!"); - intel_hdmi_unset_edid(connector); + /* + * We are here, means there is a hotplug or a force + * detection. Clear the cached EDID and probe the + * DDC bus to check the current status of HDMI. + */ + intel_hdmi_unset_edid(&intel_connector->base); + if (intel_hdmi_set_edid(&intel_connector->base, live_status)) + DRM_DEBUG_DRIVER("DDC probe: got EDID\n"); + else + DRM_DEBUG_DRIVER("DDC probe: no EDID\n"); +} - if (intel_hdmi_set_edid(connector, live_status)) { +static enum drm_connector_status +intel_hdmi_detect(struct drm_connector *connector, bool force) +{ + enum drm_connector_status status; + struct intel_connector *intel_connector = + to_intel_connector(connector); + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, connector->name); + + /* + * There are many userspace calls which probe EDID from + * detect path. In case of multiple hotplug/unplug, these + * can cause race conditions while probing EDID. Also its + * waste of CPU cycles to read the EDID again and again + * unless there is a real hotplug. + * So, rely on hotplugs and init to read edid. + * Check connector status based on availability of cached EDID. + */ + + if (intel_connector->detect_edid) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; status = connector_status_connected; - } else + DRM_DEBUG_DRIVER("hdmi status = connected\n"); + } else { status = connector_status_disconnected; + DRM_DEBUG_DRIVER("hdmi status = disconnected\n"); + } return status; } @@ -2114,6 +2145,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_connector->unregister = intel_connector_unregister; intel_hdmi_add_properties(intel_hdmi, connector); + intel_encoder->hot_plug = intel_hdmi_hot_plug; intel_connector_attach_encoder(intel_connector, intel_encoder); drm_connector_register(connector); From 2493f21f56316ad55508f173463ebf0b3f0a15bb Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 5 Oct 2015 10:01:13 +0300 Subject: [PATCH 099/134] drm/i915: Rename DP link training functions The link training functions had confusing names. The start function actually does the clock recovery phase of the link training, and the complete function does the channel equalization. So call them that instead. Also, every call to intel_dp_start_link_train() was followed by a call to intel_dp_complete_link_train(), so add a new start function that calls clock_recory and channel_equalization. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 1 - drivers/gpu/drm/i915/intel_dp.c | 22 +++++++++++++--------- drivers/gpu/drm/i915/intel_dp_mst.c | 1 - drivers/gpu/drm/i915/intel_drv.h | 1 - 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b3f1748fab97..b25e99a432fb 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2320,7 +2320,6 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); - intel_dp_complete_link_train(intel_dp); if (port != PORT_A || INTEL_INFO(dev)->gen >= 9) intel_dp_stop_link_train(intel_dp); } else if (type == INTEL_OUTPUT_HDMI) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 19cbc2ef542c..8d34ca7b287a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2604,7 +2604,6 @@ static void intel_enable_dp(struct intel_encoder *encoder) intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); - intel_dp_complete_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); if (crtc->config->has_audio) { @@ -3691,8 +3690,8 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) } /* Enable corresponding port and start training pattern 1 */ -void -intel_dp_start_link_train(struct intel_dp *intel_dp) +static void +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) { struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base; struct drm_device *dev = encoder->dev; @@ -3805,8 +3804,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) intel_dp->DP = DP; } -void -intel_dp_complete_link_train(struct intel_dp *intel_dp) +static void +intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -3859,7 +3858,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { intel_dp->train_set_valid = false; - intel_dp_start_link_train(intel_dp); + intel_dp_link_training_clock_recovery(intel_dp); intel_dp_set_link_train(intel_dp, &DP, training_pattern | DP_LINK_SCRAMBLING_DISABLE); @@ -3876,7 +3875,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* Try 5 times, then try clock recovery if that fails */ if (tries > 5) { intel_dp->train_set_valid = false; - intel_dp_start_link_train(intel_dp); + intel_dp_link_training_clock_recovery(intel_dp); intel_dp_set_link_train(intel_dp, &DP, training_pattern | DP_LINK_SCRAMBLING_DISABLE); @@ -3909,6 +3908,13 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp) DP_TRAINING_PATTERN_DISABLE); } +void +intel_dp_start_link_train(struct intel_dp *intel_dp) +{ + intel_dp_link_training_clock_recovery(intel_dp); + intel_dp_link_training_channel_equalization(intel_dp); +} + static void intel_dp_link_down(struct intel_dp *intel_dp) { @@ -4377,7 +4383,6 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) { DRM_DEBUG_KMS("channel EQ not ok, retraining\n"); intel_dp_start_link_train(intel_dp); - intel_dp_complete_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); } @@ -4468,7 +4473,6 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", intel_encoder->base.name); intel_dp_start_link_train(intel_dp); - intel_dp_complete_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); } } diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index ca4d0220ecd4..15372598b2c3 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -188,7 +188,6 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) intel_dp_start_link_train(intel_dp); - intel_dp_complete_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 563c4f1e3685..e320825abd95 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1217,7 +1217,6 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, void intel_dp_set_link_params(struct intel_dp *intel_dp, const struct intel_crtc_state *pipe_config); void intel_dp_start_link_train(struct intel_dp *intel_dp); -void intel_dp_complete_link_train(struct intel_dp *intel_dp); void intel_dp_stop_link_train(struct intel_dp *intel_dp); void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); void intel_dp_encoder_destroy(struct drm_encoder *encoder); From b248e6548e344a26fc92c57772fd4224a490bca9 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 5 Oct 2015 16:21:11 +0800 Subject: [PATCH 100/134] drm/i915/bxt: vlv_dsi_reset_clocks() can be static Signed-off-by: Fengguang Wu Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 22c1ea9d3748..cb3cf3986212 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -419,7 +419,7 @@ u32 bxt_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) return pclk; } -void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) +static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) { u32 temp; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -577,7 +577,7 @@ void intel_disable_dsi_pll(struct intel_encoder *encoder) bxt_disable_dsi_pll(encoder); } -void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) +static void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) { u32 tmp; struct drm_device *dev = encoder->base.dev; From e9f24d5fb7cf3628b195b18ff3ac4e37937ceeae Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 5 Oct 2015 13:26:36 +0100 Subject: [PATCH 101/134] drm/i915: Clean up associated VMAs on context destruction Prevent leaking VMAs and PPGTT VMs when objects are imported via flink. Scenario is that any VMAs created by the importer will be left dangling after the importer exits, or destroys the PPGTT context with which they are associated. This is caused by object destruction not running when the importer closes the buffer object handle due the reference held by the exporter. This also leaks the VM since the VMA has a reference on it. In practice these leaks can be observed by stopping and starting the X server on a kernel with fbcon compiled in. Every time X server exits another VMA will be leaked against the fbcon's frame buffer object. Also on systems where flink buffer sharing is used extensively, like Android, this leak has even more serious consequences. This version is takes a general approach from the earlier work by Rafael Barbalho (drm/i915: Clean-up PPGTT on context destruction) and tries to incorporate the subsequent discussion between Chris Wilson and Daniel Vetter. v2: Removed immediate cleanup on object retire - it was causing a recursive VMA unbind via i915_gem_object_wait_rendering. And it is in fact not even needed since by definition context cleanup worker runs only after the last context reference has been dropped, hence all VMAs against the VM belonging to the context are already on the inactive list. v3: Previous version could deadlock since VMA unbind waits on any rendering on an object to complete. Objects can be busy in a different VM which would mean that the cleanup loop would do the wait with the struct mutex held. This is an even simpler approach where we just unbind VMAs without waiting since we know all VMAs belonging to this VM are idle, and there is nothing in flight, at the point context destructor runs. v4: Double underscore prefix for __915_vma_unbind_no_wait and a commit message typo fix. (Michel Thierry) Note that this is just a partial/interim fix since we have a bit a fundamental issue with cleaning up, e.g. https://bugs.freedesktop.org/show_bug.cgi?id=87729 Signed-off-by: Tvrtko Ursulin Testcase: igt/gem_ppgtt.c/flink-and-exit-vma-leak Reviewed-by: Michel Thierry Cc: Daniel Vetter Cc: Chris Wilson Cc: Rafael Barbalho Cc: Michel Thierry [danvet: Add a note that this isn't everything.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_gem.c | 20 ++++++++++++++++---- drivers/gpu/drm/i915/i915_gem_context.c | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 35bf5cb04785..c93f9a14eae7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2839,6 +2839,11 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags); int __must_check i915_vma_unbind(struct i915_vma *vma); +/* + * BEWARE: Do not use the function below unless you can _absolutely_ + * _guarantee_ VMA in question is _not in use_ anywhere. + */ +int __must_check __i915_vma_unbind_no_wait(struct i915_vma *vma); int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f0cfbb9ee12c..52642aff1dab 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3208,7 +3208,7 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) old_write_domain); } -int i915_vma_unbind(struct i915_vma *vma) +static int __i915_vma_unbind(struct i915_vma *vma, bool wait) { struct drm_i915_gem_object *obj = vma->obj; struct drm_i915_private *dev_priv = obj->base.dev->dev_private; @@ -3227,9 +3227,11 @@ int i915_vma_unbind(struct i915_vma *vma) BUG_ON(obj->pages == NULL); - ret = i915_gem_object_wait_rendering(obj, false); - if (ret) - return ret; + if (wait) { + ret = i915_gem_object_wait_rendering(obj, false); + if (ret) + return ret; + } if (i915_is_ggtt(vma->vm) && vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) { @@ -3274,6 +3276,16 @@ int i915_vma_unbind(struct i915_vma *vma) return 0; } +int i915_vma_unbind(struct i915_vma *vma) +{ + return __i915_vma_unbind(vma, true); +} + +int __i915_vma_unbind_no_wait(struct i915_vma *vma) +{ + return __i915_vma_unbind(vma, false); +} + int i915_gpu_idle(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 74aa0c9929ba..680b4c9f6b73 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -133,6 +133,23 @@ static int get_context_size(struct drm_device *dev) return ret; } +static void i915_gem_context_clean(struct intel_context *ctx) +{ + struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; + struct i915_vma *vma, *next; + + if (WARN_ON_ONCE(!ppgtt)) + return; + + WARN_ON(!list_empty(&ppgtt->base.active_list)); + + list_for_each_entry_safe(vma, next, &ppgtt->base.inactive_list, + mm_list) { + if (WARN_ON(__i915_vma_unbind_no_wait(vma))) + break; + } +} + void i915_gem_context_free(struct kref *ctx_ref) { struct intel_context *ctx = container_of(ctx_ref, typeof(*ctx), ref); @@ -142,6 +159,13 @@ void i915_gem_context_free(struct kref *ctx_ref) if (i915.enable_execlists) intel_lr_context_free(ctx); + /* + * This context is going away and we need to remove all VMAs still + * around. This is to handle imported shared objects for which + * destructor did not run when their handles were closed. + */ + i915_gem_context_clean(ctx); + i915_ppgtt_put(ctx->ppgtt); if (ctx->legacy_hw_ctx.rcs_state) From 24dfd0736c9fc01d096e5760c656032b5a07e962 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Fri, 2 Oct 2015 14:16:53 +0100 Subject: [PATCH 102/134] drm/i915: prevent out of range pt in the PDE macros (take 3) We tried to fix this in commit fdc454c1484a ("drm/i915: Prevent out of range pt in gen6_for_each_pde"). But the static analyzer still complains that, just before we break due to "iter < I915_PDES", we do "pt = (pd)->page_table[iter]" with an iter value that is bigger than I915_PDES. Of course, this isn't really a problem since no one uses pt outside the macro. Still, every single new usage of the macro will create a new issue for us to mark as a false positive. Also, Paulo re-started the discussion a while ago [1], but didn't end up implemented. In order to "solve" this "problem", this patch takes the ideas from Chris and Dave, but that check would change the desired behavior of the code, because the object (for example pdp->page_directory[iter]) can be null during init/alloc, and C would take this as false, breaking the for loop immediately. This has been already verified with "static analysis tools". [1]http://lists.freedesktop.org/archives/intel-gfx/2015-June/068548.html v2: Make it a single statement, while preventing the common subexpression elimination (Chris) Cc: Paulo Zanoni Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Michel Thierry Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 9fbb07d6eaad..a216397ead52 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -394,7 +394,8 @@ struct i915_hw_ppgtt { */ #define gen6_for_each_pde(pt, pd, start, length, temp, iter) \ for (iter = gen6_pde_index(start); \ - pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \ + length > 0 && iter < I915_PDES ? \ + (pt = (pd)->page_table[iter]), 1 : 0; \ iter++, \ temp = ALIGN(start+1, 1 << GEN6_PDE_SHIFT) - start, \ temp = min_t(unsigned, temp, length), \ @@ -459,7 +460,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr) */ #define gen8_for_each_pde(pt, pd, start, length, temp, iter) \ for (iter = gen8_pde_index(start); \ - pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \ + length > 0 && iter < I915_PDES ? \ + (pt = (pd)->page_table[iter]), 1 : 0; \ iter++, \ temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \ temp = min(temp, length), \ @@ -467,8 +469,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr) #define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \ for (iter = gen8_pdpe_index(start); \ - pd = (pdp)->page_directory[iter], \ - length > 0 && (iter < I915_PDPES_PER_PDP(dev)); \ + length > 0 && (iter < I915_PDPES_PER_PDP(dev)) ? \ + (pd = (pdp)->page_directory[iter]), 1 : 0; \ iter++, \ temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \ temp = min(temp, length), \ @@ -476,8 +478,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr) #define gen8_for_each_pml4e(pdp, pml4, start, length, temp, iter) \ for (iter = gen8_pml4e_index(start); \ - pdp = (pml4)->pdps[iter], \ - length > 0 && iter < GEN8_PML4ES_PER_PML4; \ + length > 0 && iter < GEN8_PML4ES_PER_PML4 ? \ + (pdp = (pml4)->pdps[iter]), 1 : 0; \ iter++, \ temp = ALIGN(start+1, 1ULL << GEN8_PML4E_SHIFT) - start, \ temp = min(temp, length), \ From 68d6c840595849c0d29f6c52bc75b44ded66b41f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:34:45 +0100 Subject: [PATCH 103/134] drm/i915: Only update the current userptr worker The userptr worker allows for a slight race condition where upon there may two or more threads calling get_user_pages for the same object. When we have the array of pages, then we serialise the update of the object. However, the worker should only overwrite the obj->userptr.work pointer if and only if it is the active one. Currently we clear it for a secondary worker with the effect that we may rarely force a second lookup. v2: Rebase and rename a variable to avoid 80cols v3: Mention v2 Signed-off-by: Chris Wilson Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_userptr.c | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index d11901d590ac..800a5394aa1e 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -571,25 +571,25 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) struct get_pages_work *work = container_of(_work, typeof(*work), work); struct drm_i915_gem_object *obj = work->obj; struct drm_device *dev = obj->base.dev; - const int num_pages = obj->base.size >> PAGE_SHIFT; + const int npages = obj->base.size >> PAGE_SHIFT; struct page **pvec; int pinned, ret; ret = -ENOMEM; pinned = 0; - pvec = kmalloc(num_pages*sizeof(struct page *), + pvec = kmalloc(npages*sizeof(struct page *), GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (pvec == NULL) - pvec = drm_malloc_ab(num_pages, sizeof(struct page *)); + pvec = drm_malloc_ab(npages, sizeof(struct page *)); if (pvec != NULL) { struct mm_struct *mm = obj->userptr.mm->mm; down_read(&mm->mmap_sem); - while (pinned < num_pages) { + while (pinned < npages) { ret = get_user_pages(work->task, mm, obj->userptr.ptr + pinned * PAGE_SIZE, - num_pages - pinned, + npages - pinned, !obj->userptr.read_only, 0, pvec + pinned, NULL); if (ret < 0) @@ -601,20 +601,20 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) } mutex_lock(&dev->struct_mutex); - if (obj->userptr.work != &work->work) { - ret = 0; - } else if (pinned == num_pages) { - ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages); - if (ret == 0) { - list_add_tail(&obj->global_list, &to_i915(dev)->mm.unbound_list); - obj->get_page.sg = obj->pages->sgl; - obj->get_page.last = 0; - - pinned = 0; + if (obj->userptr.work == &work->work) { + if (pinned == npages) { + ret = __i915_gem_userptr_set_pages(obj, pvec, npages); + if (ret == 0) { + list_add_tail(&obj->global_list, + &to_i915(dev)->mm.unbound_list); + obj->get_page.sg = obj->pages->sgl; + obj->get_page.last = 0; + pinned = 0; + } } + obj->userptr.work = ERR_PTR(ret); } - obj->userptr.work = ERR_PTR(ret); obj->userptr.workers--; drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); From e4b946bfe1e36680e27a5f39163980979fa61a5d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:34:46 +0100 Subject: [PATCH 104/134] drm/i915: Fix userptr deadlock with aliased GTT mmappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Michał Winiarski found a really evil way to trigger a struct_mutex deadlock with userptr. He found that if he allocated a userptr bo and then GTT mmaped another bo, or even itself, at the same address as the userptr using MAP_FIXED, he could then cause a deadlock any time we then had to invalidate the GTT mmappings (so at will). Tvrtko then found by repeatedly allocating GTT mmappings he could alias with an old userptr mmap and also trigger the deadlock. To counter act the deadlock, we make the observation that we only need to take the struct_mutex if the object has any pages to revoke, and that before userspace can alias with the userptr address space, it must have invalidated the userptr->pages. Thus if we can check for those pages outside of the struct_mutex, we can avoid the deadlock. To do so we introduce a separate flag for userptr objects that we can inspect from the mmu-notifier underneath its spinlock. The patch makes one eye-catching change. That is the removal serial=0 after detecting a to-be-freed object inside the invalidate walker. I felt setting serial=0 was a questionable pessimisation: it denies us the chance to reuse the current iterator for the next loop (before it is freed) and being explicit makes the reader question the validity of the locking (since the object-free race could occur elsewhere). The serialisation of the iterator is through the spinlock, if the object is freed before the next loop then the notifier.serial will be incremented and we start the walk from the beginning as we detect the invalid cache. To try and tame the error paths and interactions with the userptr->active flag, we have to do a fair amount of rearranging of get_pages_userptr(). v2: Grammar fixes v3: Reorder set-active so that it is only set when obj->pages is set (and so needs cancellation). Only the order of setting obj->pages and the active-flag is crucial. Calling gup after invalidate-range begin means the userptr sees the new set of backing storage (and so will not need to invalidate its new pages), but we have to be careful not to set the active-flag prior to successfully establishing obj->pages. v4: Take the active->flag early so we know in the mmu-notifier when we have to cancel a pending gup-worker. v5: Rearrange the error path so that is not so convoluted v6: Set pinned to 0 when negative before calling release_pages() Reported-by: Michał Winiarski Testcase: igt/gem_userptr_blits/map-fixed* Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Tvrtko Ursulin Cc: stable@vger.kernel.org Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_userptr.c | 173 +++++++++++++++--------- 1 file changed, 108 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 800a5394aa1e..161f7fbf5b76 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -59,6 +59,7 @@ struct i915_mmu_object { struct interval_tree_node it; struct list_head link; struct drm_i915_gem_object *obj; + bool active; bool is_linear; }; @@ -114,7 +115,8 @@ static void *invalidate_range__linear(struct i915_mmu_notifier *mn, obj = mo->obj; - if (!kref_get_unless_zero(&obj->base.refcount)) + if (!mo->active || + !kref_get_unless_zero(&obj->base.refcount)) continue; spin_unlock(&mn->lock); @@ -151,7 +153,8 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, else it = interval_tree_iter_first(&mn->objects, start, end); if (it != NULL) { - obj = container_of(it, struct i915_mmu_object, it)->obj; + struct i915_mmu_object *mo = + container_of(it, struct i915_mmu_object, it); /* The mmu_object is released late when destroying the * GEM object so it is entirely possible to gain a @@ -160,11 +163,9 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, * the struct_mutex - and consequently use it after it * is freed and then double free it. */ - if (!kref_get_unless_zero(&obj->base.refcount)) { - spin_unlock(&mn->lock); - serial = 0; - continue; - } + if (mo->active && + kref_get_unless_zero(&mo->obj->base.refcount)) + obj = mo->obj; serial = mn->serial; } @@ -565,6 +566,30 @@ __i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj, return ret; } +static void +__i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, + bool value) +{ + /* During mm_invalidate_range we need to cancel any userptr that + * overlaps the range being invalidated. Doing so requires the + * struct_mutex, and that risks recursion. In order to cause + * recursion, the user must alias the userptr address space with + * a GTT mmapping (possible with a MAP_FIXED) - then when we have + * to invalidate that mmaping, mm_invalidate_range is called with + * the userptr address *and* the struct_mutex held. To prevent that + * we set a flag under the i915_mmu_notifier spinlock to indicate + * whether this object is valid. + */ +#if defined(CONFIG_MMU_NOTIFIER) + if (obj->userptr.mmu_object == NULL) + return; + + spin_lock(&obj->userptr.mmu_object->mn->lock); + obj->userptr.mmu_object->active = value; + spin_unlock(&obj->userptr.mmu_object->mn->lock); +#endif +} + static void __i915_gem_userptr_get_pages_worker(struct work_struct *_work) { @@ -613,6 +638,8 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) } } obj->userptr.work = ERR_PTR(ret); + if (ret) + __i915_gem_userptr_set_active(obj, false); } obj->userptr.workers--; @@ -626,12 +653,61 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) kfree(work); } +static int +__i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj, + bool *active) +{ + struct get_pages_work *work; + + /* Spawn a worker so that we can acquire the + * user pages without holding our mutex. Access + * to the user pages requires mmap_sem, and we have + * a strict lock ordering of mmap_sem, struct_mutex - + * we already hold struct_mutex here and so cannot + * call gup without encountering a lock inversion. + * + * Userspace will keep on repeating the operation + * (thanks to EAGAIN) until either we hit the fast + * path or the worker completes. If the worker is + * cancelled or superseded, the task is still run + * but the results ignored. (This leads to + * complications that we may have a stray object + * refcount that we need to be wary of when + * checking for existing objects during creation.) + * If the worker encounters an error, it reports + * that error back to this function through + * obj->userptr.work = ERR_PTR. + */ + if (obj->userptr.workers >= I915_GEM_USERPTR_MAX_WORKERS) + return -EAGAIN; + + work = kmalloc(sizeof(*work), GFP_KERNEL); + if (work == NULL) + return -ENOMEM; + + obj->userptr.work = &work->work; + obj->userptr.workers++; + + work->obj = obj; + drm_gem_object_reference(&obj->base); + + work->task = current; + get_task_struct(work->task); + + INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); + schedule_work(&work->work); + + *active = true; + return -EAGAIN; +} + static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) { const int num_pages = obj->base.size >> PAGE_SHIFT; struct page **pvec; int pinned, ret; + bool active; /* If userspace should engineer that these pages are replaced in * the vma between us binding this page into the GTT and completion @@ -649,6 +725,18 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) * to the vma (discard or cloning) which should prevent the more * egregious cases from causing harm. */ + if (IS_ERR(obj->userptr.work)) { + /* active flag will have been dropped already by the worker */ + ret = PTR_ERR(obj->userptr.work); + obj->userptr.work = NULL; + return ret; + } + if (obj->userptr.work) + /* active flag should still be held for the pending work */ + return -EAGAIN; + + /* Let the mmu-notifier know that we have begun and need cancellation */ + __i915_gem_userptr_set_active(obj, true); pvec = NULL; pinned = 0; @@ -657,73 +745,27 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); if (pvec == NULL) { pvec = drm_malloc_ab(num_pages, sizeof(struct page *)); - if (pvec == NULL) + if (pvec == NULL) { + __i915_gem_userptr_set_active(obj, false); return -ENOMEM; + } } pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages, !obj->userptr.read_only, pvec); } - if (pinned < num_pages) { - if (pinned < 0) { - ret = pinned; - pinned = 0; - } else { - /* Spawn a worker so that we can acquire the - * user pages without holding our mutex. Access - * to the user pages requires mmap_sem, and we have - * a strict lock ordering of mmap_sem, struct_mutex - - * we already hold struct_mutex here and so cannot - * call gup without encountering a lock inversion. - * - * Userspace will keep on repeating the operation - * (thanks to EAGAIN) until either we hit the fast - * path or the worker completes. If the worker is - * cancelled or superseded, the task is still run - * but the results ignored. (This leads to - * complications that we may have a stray object - * refcount that we need to be wary of when - * checking for existing objects during creation.) - * If the worker encounters an error, it reports - * that error back to this function through - * obj->userptr.work = ERR_PTR. - */ - ret = -EAGAIN; - if (obj->userptr.work == NULL && - obj->userptr.workers < I915_GEM_USERPTR_MAX_WORKERS) { - struct get_pages_work *work; - work = kmalloc(sizeof(*work), GFP_KERNEL); - if (work != NULL) { - obj->userptr.work = &work->work; - obj->userptr.workers++; - - work->obj = obj; - drm_gem_object_reference(&obj->base); - - work->task = current; - get_task_struct(work->task); - - INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); - schedule_work(&work->work); - } else - ret = -ENOMEM; - } else { - if (IS_ERR(obj->userptr.work)) { - ret = PTR_ERR(obj->userptr.work); - obj->userptr.work = NULL; - } - } - } - } else { + active = false; + if (pinned < 0) + ret = pinned, pinned = 0; + else if (pinned < num_pages) + ret = __i915_gem_userptr_get_pages_schedule(obj, &active); + else ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages); - if (ret == 0) { - obj->userptr.work = NULL; - pinned = 0; - } + if (ret) { + __i915_gem_userptr_set_active(obj, active); + release_pages(pvec, pinned, 0); } - - release_pages(pvec, pinned, 0); drm_free_large(pvec); return ret; } @@ -734,6 +776,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj) struct sg_page_iter sg_iter; BUG_ON(obj->userptr.work != NULL); + __i915_gem_userptr_set_active(obj, false); if (obj->madv != I915_MADV_WILLNEED) obj->dirty = 0; From 380996aab50eea1d66269e1633cd2f971f06da6d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:34:47 +0100 Subject: [PATCH 105/134] drm/i915: Use a task to cancel the userptr on invalidate_range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whilst discussing possible ways to trigger an invalidate_range on a userptr with an aliased GGTT mmapping (and so cause a struct_mutex deadlock), the conclusion is that we can, and we must, prevent any possible deadlock by avoiding taking the mutex at all during invalidate_range. This has numerous advantages all of which stem from avoid the sleeping function from inside the unknown context. In particular, it simplifies the invalidate_range because we no longer have to juggle the spinlock/mutex and can just hold the spinlock for the entire walk. To compensate, we have to make get_pages a bit more complicated in order to serialise with a pending cancel_userptr worker. As we hold the struct_mutex, we have no choice but to return EAGAIN and hope that the worker is then flushed before we retry after reacquiring the struct_mutex. The important caveat is that the invalidate_range itself is no longer synchronous. There exists a small but definite period in time in which the old PTE's page remain accessible via the GPU. Note however that the physical pages themselves are not invalidated by the mmu_notifier, just the CPU view of the address space. The impact should be limited to a delay in pages being flushed, rather than a possibility of writing to the wrong pages. The only race condition that this worsens is remapping an userptr active on the GPU where fresh work may still reference the old pages due to struct_mutex contention. Given that userspace is racing with the GPU, it is fair to say that the results are undefined. v2: Only queue (and importantly only take one refcnt) the worker once. Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_userptr.c | 140 ++++++++++-------------- 1 file changed, 57 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 161f7fbf5b76..1b3b451b6658 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -50,7 +50,6 @@ struct i915_mmu_notifier { struct mmu_notifier mn; struct rb_root objects; struct list_head linear; - unsigned long serial; bool has_linear; }; @@ -59,14 +58,16 @@ struct i915_mmu_object { struct interval_tree_node it; struct list_head link; struct drm_i915_gem_object *obj; + struct work_struct work; bool active; bool is_linear; }; -static unsigned long cancel_userptr(struct drm_i915_gem_object *obj) +static void __cancel_userptr__worker(struct work_struct *work) { + struct i915_mmu_object *mo = container_of(work, typeof(*mo), work); + struct drm_i915_gem_object *obj = mo->obj; struct drm_device *dev = obj->base.dev; - unsigned long end; mutex_lock(&dev->struct_mutex); /* Cancel any active worker and force us to re-evaluate gup */ @@ -89,46 +90,28 @@ static unsigned long cancel_userptr(struct drm_i915_gem_object *obj) dev_priv->mm.interruptible = was_interruptible; } - end = obj->userptr.ptr + obj->base.size; - drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); - - return end; } -static void *invalidate_range__linear(struct i915_mmu_notifier *mn, - struct mm_struct *mm, - unsigned long start, - unsigned long end) +static unsigned long cancel_userptr(struct i915_mmu_object *mo) { - struct i915_mmu_object *mo; - unsigned long serial; + unsigned long end = mo->obj->userptr.ptr + mo->obj->base.size; -restart: - serial = mn->serial; - list_for_each_entry(mo, &mn->linear, link) { - struct drm_i915_gem_object *obj; - - if (mo->it.last < start || mo->it.start > end) - continue; - - obj = mo->obj; - - if (!mo->active || - !kref_get_unless_zero(&obj->base.refcount)) - continue; - - spin_unlock(&mn->lock); - - cancel_userptr(obj); - - spin_lock(&mn->lock); - if (serial != mn->serial) - goto restart; + /* The mmu_object is released late when destroying the + * GEM object so it is entirely possible to gain a + * reference on an object in the process of being freed + * since our serialisation is via the spinlock and not + * the struct_mutex - and consequently use it after it + * is freed and then double free it. + */ + if (mo->active && kref_get_unless_zero(&mo->obj->base.refcount)) { + schedule_work(&mo->work); + /* only schedule one work packet to avoid the refleak */ + mo->active = false; } - return NULL; + return end; } static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, @@ -136,45 +119,32 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, unsigned long start, unsigned long end) { - struct i915_mmu_notifier *mn = container_of(_mn, struct i915_mmu_notifier, mn); - struct interval_tree_node *it = NULL; - unsigned long next = start; - unsigned long serial = 0; + struct i915_mmu_notifier *mn = + container_of(_mn, struct i915_mmu_notifier, mn); + struct i915_mmu_object *mo; - end--; /* interval ranges are inclusive, but invalidate range is exclusive */ - while (next < end) { - struct drm_i915_gem_object *obj = NULL; + /* interval ranges are inclusive, but invalidate range is exclusive */ + end--; - spin_lock(&mn->lock); - if (mn->has_linear) - it = invalidate_range__linear(mn, mm, start, end); - else if (serial == mn->serial) - it = interval_tree_iter_next(it, next, end); - else - it = interval_tree_iter_first(&mn->objects, start, end); - if (it != NULL) { - struct i915_mmu_object *mo = - container_of(it, struct i915_mmu_object, it); + spin_lock(&mn->lock); + if (mn->has_linear) { + list_for_each_entry(mo, &mn->linear, link) { + if (mo->it.last < start || mo->it.start > end) + continue; - /* The mmu_object is released late when destroying the - * GEM object so it is entirely possible to gain a - * reference on an object in the process of being freed - * since our serialisation is via the spinlock and not - * the struct_mutex - and consequently use it after it - * is freed and then double free it. - */ - if (mo->active && - kref_get_unless_zero(&mo->obj->base.refcount)) - obj = mo->obj; - - serial = mn->serial; + cancel_userptr(mo); } - spin_unlock(&mn->lock); - if (obj == NULL) - return; + } else { + struct interval_tree_node *it; - next = cancel_userptr(obj); + it = interval_tree_iter_first(&mn->objects, start, end); + while (it) { + mo = container_of(it, struct i915_mmu_object, it); + start = cancel_userptr(mo); + it = interval_tree_iter_next(it, start, end); + } } + spin_unlock(&mn->lock); } static const struct mmu_notifier_ops i915_gem_userptr_notifier = { @@ -194,7 +164,6 @@ i915_mmu_notifier_create(struct mm_struct *mm) spin_lock_init(&mn->lock); mn->mn.ops = &i915_gem_userptr_notifier; mn->objects = RB_ROOT; - mn->serial = 1; INIT_LIST_HEAD(&mn->linear); mn->has_linear = false; @@ -208,12 +177,6 @@ i915_mmu_notifier_create(struct mm_struct *mm) return mn; } -static void __i915_mmu_notifier_update_serial(struct i915_mmu_notifier *mn) -{ - if (++mn->serial == 0) - mn->serial = 1; -} - static int i915_mmu_notifier_add(struct drm_device *dev, struct i915_mmu_notifier *mn, @@ -260,10 +223,9 @@ i915_mmu_notifier_add(struct drm_device *dev, } else interval_tree_insert(&mo->it, &mn->objects); - if (ret == 0) { + if (ret == 0) list_add(&mo->link, &mn->linear); - __i915_mmu_notifier_update_serial(mn); - } + spin_unlock(&mn->lock); mutex_unlock(&dev->struct_mutex); @@ -291,7 +253,6 @@ i915_mmu_notifier_del(struct i915_mmu_notifier *mn, mn->has_linear = i915_mmu_notifier_has_linear(mn); else interval_tree_remove(&mo->it, &mn->objects); - __i915_mmu_notifier_update_serial(mn); spin_unlock(&mn->lock); } @@ -358,6 +319,7 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, mo->it.start = obj->userptr.ptr; mo->it.last = mo->it.start + obj->base.size - 1; mo->obj = obj; + INIT_WORK(&mo->work, __cancel_userptr__worker); ret = i915_mmu_notifier_add(obj->base.dev, mn, mo); if (ret) { @@ -566,10 +528,12 @@ __i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj, return ret; } -static void +static int __i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, bool value) { + int ret = 0; + /* During mm_invalidate_range we need to cancel any userptr that * overlaps the range being invalidated. Doing so requires the * struct_mutex, and that risks recursion. In order to cause @@ -582,12 +546,20 @@ __i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, */ #if defined(CONFIG_MMU_NOTIFIER) if (obj->userptr.mmu_object == NULL) - return; + return 0; spin_lock(&obj->userptr.mmu_object->mn->lock); - obj->userptr.mmu_object->active = value; + /* In order to serialise get_pages with an outstanding + * cancel_userptr, we must drop the struct_mutex and try again. + */ + if (!value || !work_pending(&obj->userptr.mmu_object->work)) + obj->userptr.mmu_object->active = value; + else + ret = -EAGAIN; spin_unlock(&obj->userptr.mmu_object->mn->lock); #endif + + return ret; } static void @@ -736,7 +708,9 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) return -EAGAIN; /* Let the mmu-notifier know that we have begun and need cancellation */ - __i915_gem_userptr_set_active(obj, true); + ret = __i915_gem_userptr_set_active(obj, true); + if (ret) + return ret; pvec = NULL; pinned = 0; From 1f2449cdd689931f5f511235899b2a0e28010e50 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 6 Oct 2015 14:47:55 +0200 Subject: [PATCH 106/134] drm/i915: Fix kerneldoc for i915_gem_shrink_all I've botched this, so let's fix it. Botched in commit eb0b44adc08c0be01a027eb009e9cdadc31e65a2 Author: Daniel Vetter Date: Wed Mar 18 14:47:59 2015 +0100 drm/i915: kerneldoc for i915_gem_shrinker.c v2: Be a good citizen^Wmaintainer and add the proper commit citation. Noticed by Jani. Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_shrinker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index f6ecbda2c604..674341708033 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -143,7 +143,7 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, } /** - * i915_gem_shrink - Shrink buffer object caches completely + * i915_gem_shrink_all - Shrink buffer object caches completely * @dev_priv: i915 device * * This is a simple wraper around i915_gem_shrink() to aggressively shrink all From 143875400b33fc20e9dd060e90034f2e9e9ffc98 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:18:25 +0100 Subject: [PATCH 107/134] drm/i915: shrinker_control->nr_to_scan is now unsigned long As the shrinker_control now passes us unsigned long targets, update our shrinker functions to match. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_shrinker.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c93f9a14eae7..85c4894241c7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3203,7 +3203,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, /* i915_gem_shrinker.c */ unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, - long target, + unsigned long target, unsigned flags); #define I915_SHRINK_PURGEABLE 0x1 #define I915_SHRINK_UNBOUND 0x2 diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 674341708033..858df2bffc9e 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -73,7 +73,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) */ unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, - long target, unsigned flags) + unsigned long target, unsigned flags) { const struct { struct list_head *list; @@ -159,7 +159,7 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv) { i915_gem_evict_everything(dev_priv->dev); - return i915_gem_shrink(dev_priv, LONG_MAX, + return i915_gem_shrink(dev_priv, -1UL, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); } From 3f4c90bd203125c807a96f18d3195cf3a1988279 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 1 Oct 2015 17:01:08 +0800 Subject: [PATCH 108/134] drm/i915: add kerneldoc for i915_audio_component Add the kerneldoc for i915_audio_component in i915_component.h Signed-off-by: Libin Yang Signed-off-by: Daniel Vetter --- include/drm/i915_component.h | 65 +++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index 89dc7d6bc1cc..30d89e0da2c6 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -30,38 +30,49 @@ */ #define MAX_PORTS 5 +/** + * struct i915_audio_component_ops - callbacks defined in gfx driver + * @owner: the module owner + * @get_power: get the POWER_DOMAIN_AUDIO power well + * @put_power: put the POWER_DOMAIN_AUDIO power well + * @codec_wake_override: Enable/Disable generating the codec wake signal + * @get_cdclk_freq: get the Core Display Clock in KHz + * @sync_audio_rate: set n/cts based on the sample rate + */ +struct i915_audio_component_ops { + struct module *owner; + void (*get_power)(struct device *); + void (*put_power)(struct device *); + void (*codec_wake_override)(struct device *, bool enable); + int (*get_cdclk_freq)(struct device *); + int (*sync_audio_rate)(struct device *, int port, int rate); +}; + +struct i915_audio_component_audio_ops { + void *audio_ptr; + /** + * Call from i915 driver, notifying the HDA driver that + * pin sense and/or ELD information has changed. + * @audio_ptr: HDA driver object + * @port: Which port has changed (PORTA / PORTB / PORTC etc) + */ + void (*pin_eld_notify)(void *audio_ptr, int port); +}; + +/** + * struct i915_audio_component - used for audio video interaction + * @dev: the device from gfx driver + * @aud_sample_rate: the array of audio sample rate per port + * @ops: callback for audio driver calling + * @audio_ops: Call from i915 driver + */ struct i915_audio_component { struct device *dev; - /** - * @aud_sample_rate: the array of audio sample rate per port - */ int aud_sample_rate[MAX_PORTS]; - const struct i915_audio_component_ops { - struct module *owner; - void (*get_power)(struct device *); - void (*put_power)(struct device *); - void (*codec_wake_override)(struct device *, bool enable); - int (*get_cdclk_freq)(struct device *); - /** - * @sync_audio_rate: set n/cts based on the sample rate - * - * Called from audio driver. After audio driver sets the - * sample rate, it will call this function to set n/cts - */ - int (*sync_audio_rate)(struct device *, int port, int rate); - } *ops; + const struct i915_audio_component_ops *ops; - const struct i915_audio_component_audio_ops { - void *audio_ptr; - /** - * Call from i915 driver, notifying the HDA driver that - * pin sense and/or ELD information has changed. - * @audio_ptr: HDA driver object - * @port: Which port has changed (PORTA / PORTB / PORTC etc) - */ - void (*pin_eld_notify)(void *audio_ptr, int port); - } *audio_ops; + const struct i915_audio_component_audio_ops *audio_ops; }; #endif /* _I915_COMPONENT_H_ */ From cb422619976f3f1b71f68f0c1b5a764e9f90fb0c Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 1 Oct 2015 17:01:09 +0800 Subject: [PATCH 109/134] drm/i915: DocBook add i915_component.h support Add the item of i915_component.h in DocBook and add the DOC for i915_component.h. Explain the struct i915_audio_component_ops and struct i915_audio_component_audio_ops usage. Signed-off-by: Libin Yang Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 1 + drivers/gpu/drm/i915/intel_audio.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index f78ca7f18bb2..a249c73ec1b5 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4051,6 +4051,7 @@ int num_ioctls; High Definition Audio !Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port !Idrivers/gpu/drm/i915/intel_audio.c +!Iinclude/drm/i915_component.h Panel Self Refresh PSR (PSR/SRD) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 72d696b0e7d4..56c2f54801c4 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -50,6 +50,11 @@ * co-operation between the graphics and audio drivers is handled via audio * related registers. (The notable exception is the power management, not * covered here.) + * + * The struct i915_audio_component is used to interact between the graphics + * and audio drivers. The struct i915_audio_component_ops *ops in it is + * defined in graphics driver and called in audio driver. The + * struct i915_audio_component_audio_ops *audio_ops is called from i915 driver. */ static const struct { From 3abafa539d2c17d46df3f47b35eb784fdf3020a1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:18:26 +0100 Subject: [PATCH 110/134] drm/i915: Add a tracepoint for the shrinker Often it is very useful to know why we suddenly purge vast tracts of memory and surprisingly up until now we didn't even have a tracepoint for when we shrink our memory. Note that there are slab_start/end tracepoints already, but those don't cover the internal recursion when we directly call into our shrinker code. Hence a separate tracepoint seems justified. Also note that we don't really need a separate tracepoint for the actual amount of pages freed since we already have an unbind tracpoint for that. Signed-off-by: Chris Wilson [danvet: Add a note that there's also slab_start/end and why they're insufficient.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_shrinker.c | 2 ++ drivers/gpu/drm/i915/i915_trace.h | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 858df2bffc9e..1b66e1d1def1 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -85,6 +85,8 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, }, *phase; unsigned long count = 0; + trace_i915_gem_shrink(dev_priv, target, flags); + /* * As we may completely rewrite the (un)bound list whilst unbinding * (due to retiring requests) we have to strictly process only diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index d0993bc814ea..04fe8491c8b6 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -107,6 +107,26 @@ TRACE_EVENT(i915_gem_object_create, TP_printk("obj=%p, size=%u", __entry->obj, __entry->size) ); +TRACE_EVENT(i915_gem_shrink, + TP_PROTO(struct drm_i915_private *i915, unsigned long target, unsigned flags), + TP_ARGS(i915, target, flags), + + TP_STRUCT__entry( + __field(int, dev) + __field(unsigned long, target) + __field(unsigned, flags) + ), + + TP_fast_assign( + __entry->dev = i915->dev->primary->index; + __entry->target = target; + __entry->flags = flags; + ), + + TP_printk("dev=%d, target=%lu, flags=%x", + __entry->dev, __entry->target, __entry->flags) +); + TRACE_EVENT(i915_vma_bind, TP_PROTO(struct i915_vma *vma, unsigned flags), TP_ARGS(vma, flags), From c9c0f5ea1b60b1f759a928505205335775e20512 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:18:27 +0100 Subject: [PATCH 111/134] drm/i915: During shrink_all we only need to idle the GPU We can forgo an evict-everything here as the shrinker operation itself will unbind any vma as required. If we explicitly idle the GPU through a switch to the default context, we not only create a request in an illegal context (e.g. whilst shrinking during execbuf with a request already allocated), but switching to the default context will not free up the memory backing the active contexts - unless in the unlikely situation that context had already been closed (and just kept arrive by being the current context). The saving is near zero and the danger real. To compensate for the loss of the forced retire, add a couple of retire-requests to i915_gem_shirnk() - this should help free up any transitive cache from the requests. Note that the second retire_requests is for the benefit of the hand-rolled execlist ctx active tracking: We need to manually kick requests to get those unpinned again. Once that's fixed we can try to remove this again. Signed-off-by: Chris Wilson [danvet: Add summary of why we need a pile of retire_requests.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_shrinker.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 1b66e1d1def1..03cf3ccc4152 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -86,6 +86,7 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, unsigned long count = 0; trace_i915_gem_shrink(dev_priv, target, flags); + i915_gem_retire_requests(dev_priv->dev); /* * As we may completely rewrite the (un)bound list whilst unbinding @@ -141,6 +142,8 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, list_splice(&still_in_list, phase->list); } + i915_gem_retire_requests(dev_priv->dev); + return count; } @@ -160,7 +163,6 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, */ unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv) { - i915_gem_evict_everything(dev_priv->dev); return i915_gem_shrink(dev_priv, -1UL, I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); } From ce8daef3580ae38fea9599e2193e4c368357c4c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:18:28 +0100 Subject: [PATCH 112/134] drm/i915: Remove dead i915_gem_evict_everything() With UMS gone, we no longer use it during suspend. And with the last user removed from the shrinker, we can remove the dead code. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem_evict.c | 45 --------------------------- 2 files changed, 46 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1626f3d79a6f..803105224e0d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3177,7 +3177,6 @@ int __must_check i915_gem_evict_something(struct drm_device *dev, unsigned long end, unsigned flags); int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); -int i915_gem_evict_everything(struct drm_device *dev); /* belongs in i915_gem_gtt.h */ static inline void i915_gem_chipset_flush(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index d09e35ed9c9a..d71a133ceff5 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -237,48 +237,3 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) return 0; } - -/** - * i915_gem_evict_everything - Try to evict all objects - * @dev: Device to evict objects for - * - * This functions tries to evict all gem objects from all address spaces. Used - * by the shrinker as a last-ditch effort and for suspend, before releasing the - * backing storage of all unbound objects. - */ -int -i915_gem_evict_everything(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_address_space *vm, *v; - bool lists_empty = true; - int ret; - - list_for_each_entry(vm, &dev_priv->vm_list, global_link) { - lists_empty = (list_empty(&vm->inactive_list) && - list_empty(&vm->active_list)); - if (!lists_empty) - lists_empty = false; - } - - if (lists_empty) - return -ENOSPC; - - trace_i915_gem_evict_everything(dev); - - /* The gpu_idle will flush everything in the write domain to the - * active list. Then we must move everything off the active list - * with retire requests. - */ - ret = i915_gpu_idle(dev); - if (ret) - return ret; - - i915_gem_retire_requests(dev); - - /* Having flushed everything, unbind() should never raise an error */ - list_for_each_entry_safe(vm, v, &dev_priv->vm_list, global_link) - WARN_ON(i915_gem_evict_vm(vm, false)); - - return 0; -} From 5763ff04dc4ebdd13d069d44513b10805ebebd8c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 1 Oct 2015 12:18:29 +0100 Subject: [PATCH 113/134] drm/i915: Avoid GPU stalls from kswapd Exclude active GPU pages from the purview of the background shrinker (kswapd), as these cause uncontrollable GPU stalls. Given that the shrinker is rerun until the freelists are satisfied, we should have opportunity in subsequent passes to recover the pages once idle. If the machine does run out of memory entirely, we have the forced idling in the oom-notifier as a means of releasing all the pages we can before an oom is prematurely executed. Note that this relies upon an up-front retire_requests to keep the inactive list in shape, which was added in a previous patch, mostly as execlist ctx pinning band-aids. Signed-off-by: Chris Wilson Reviewed-by: Damien Lespiau [danvet: Add note about retire_requests.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_shrinker.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 803105224e0d..b39b5cc0c096 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3212,6 +3212,7 @@ unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, #define I915_SHRINK_PURGEABLE 0x1 #define I915_SHRINK_UNBOUND 0x2 #define I915_SHRINK_BOUND 0x4 +#define I915_SHRINK_ACTIVE 0x8 unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); void i915_gem_shrinker_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 03cf3ccc4152..f7df54a8ee2b 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -126,6 +126,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, obj->madv != I915_MADV_DONTNEED) continue; + if ((flags & I915_SHRINK_ACTIVE) == 0 && obj->active) + continue; + drm_gem_object_reference(&obj->base); /* For the unbound phase, this should be a no-op! */ @@ -164,7 +167,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv) { return i915_gem_shrink(dev_priv, -1UL, - I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); + I915_SHRINK_BOUND | + I915_SHRINK_UNBOUND | + I915_SHRINK_ACTIVE); } static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock) @@ -217,7 +222,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) count += obj->base.size >> PAGE_SHIFT; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - if (obj->pages_pin_count == num_vma_bound(obj)) + if (!obj->active && obj->pages_pin_count == num_vma_bound(obj)) count += obj->base.size >> PAGE_SHIFT; } From 2f5945bc9076bd7b1086c1b4ac47dea8ab336e57 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 6 Oct 2015 11:39:55 +0100 Subject: [PATCH 114/134] drm/i915: Kill DRI1 cliprects Passing cliprects into the kernel for it to re-execute the batch buffer with different CMD_DRAWRECT died out long ago. As DRI1 support has been removed from the kernel, we can now simply reject any execbuf trying to use this "feature". To keep Daniel happy with the prospect of being able to reuse these fields in the next decade, continue to ensure that current userspace is not passing garbage in through the dead fields. v2: Fix the cliprects_ptr check Signed-off-by: Chris Wilson Cc: Daniel Vetter Reviewed-by: Tvrtko Ursulin Reviewed-by: Dave Gordon Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 154 +++++---------------- drivers/gpu/drm/i915/intel_lrc.c | 15 -- 2 files changed, 31 insertions(+), 138 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index edc17befc37d..6ed7d63a0688 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -945,7 +945,21 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS) return false; - return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0; + /* Kernel clipping was a DRI1 misfeature */ + if (exec->num_cliprects || exec->cliprects_ptr) + return false; + + if (exec->DR4 == 0xffffffff) { + DRM_DEBUG("UXA submitting garbage DR4, fixing up\n"); + exec->DR4 = 0; + } + if (exec->DR1 || exec->DR4) + return false; + + if ((exec->batch_start_offset | exec->batch_len) & 0x7) + return false; + + return true; } static int @@ -1109,47 +1123,6 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, return 0; } -static int -i915_emit_box(struct drm_i915_gem_request *req, - struct drm_clip_rect *box, - int DR1, int DR4) -{ - struct intel_engine_cs *ring = req->ring; - int ret; - - if (box->y2 <= box->y1 || box->x2 <= box->x1 || - box->y2 <= 0 || box->x2 <= 0) { - DRM_ERROR("Bad box %d,%d..%d,%d\n", - box->x1, box->y1, box->x2, box->y2); - return -EINVAL; - } - - if (INTEL_INFO(ring->dev)->gen >= 4) { - ret = intel_ring_begin(req, 4); - if (ret) - return ret; - - intel_ring_emit(ring, GFX_OP_DRAWRECT_INFO_I965); - intel_ring_emit(ring, (box->x1 & 0xffff) | box->y1 << 16); - intel_ring_emit(ring, ((box->x2 - 1) & 0xffff) | (box->y2 - 1) << 16); - intel_ring_emit(ring, DR4); - } else { - ret = intel_ring_begin(req, 6); - if (ret) - return ret; - - intel_ring_emit(ring, GFX_OP_DRAWRECT_INFO); - intel_ring_emit(ring, DR1); - intel_ring_emit(ring, (box->x1 & 0xffff) | box->y1 << 16); - intel_ring_emit(ring, ((box->x2 - 1) & 0xffff) | (box->y2 - 1) << 16); - intel_ring_emit(ring, DR4); - intel_ring_emit(ring, 0); - } - intel_ring_advance(ring); - - return 0; -} - static struct drm_i915_gem_object* i915_gem_execbuffer_parse(struct intel_engine_cs *ring, struct drm_i915_gem_exec_object2 *shadow_exec_entry, @@ -1208,65 +1181,21 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, struct list_head *vmas) { - struct drm_clip_rect *cliprects = NULL; struct drm_device *dev = params->dev; struct intel_engine_cs *ring = params->ring; struct drm_i915_private *dev_priv = dev->dev_private; u64 exec_start, exec_len; int instp_mode; u32 instp_mask; - int i, ret = 0; - - if (args->num_cliprects != 0) { - if (ring != &dev_priv->ring[RCS]) { - DRM_DEBUG("clip rectangles are only valid with the render ring\n"); - return -EINVAL; - } - - if (INTEL_INFO(dev)->gen >= 5) { - DRM_DEBUG("clip rectangles are only valid on pre-gen5\n"); - return -EINVAL; - } - - if (args->num_cliprects > UINT_MAX / sizeof(*cliprects)) { - DRM_DEBUG("execbuf with %u cliprects\n", - args->num_cliprects); - return -EINVAL; - } - - cliprects = kcalloc(args->num_cliprects, - sizeof(*cliprects), - GFP_KERNEL); - if (cliprects == NULL) { - ret = -ENOMEM; - goto error; - } - - if (copy_from_user(cliprects, - to_user_ptr(args->cliprects_ptr), - sizeof(*cliprects)*args->num_cliprects)) { - ret = -EFAULT; - goto error; - } - } else { - if (args->DR4 == 0xffffffff) { - DRM_DEBUG("UXA submitting garbage DR4, fixing up\n"); - args->DR4 = 0; - } - - if (args->DR1 || args->DR4 || args->cliprects_ptr) { - DRM_DEBUG("0 cliprects but dirt in cliprects fields\n"); - return -EINVAL; - } - } + int ret; ret = i915_gem_execbuffer_move_to_gpu(params->request, vmas); if (ret) - goto error; + return ret; ret = i915_switch_context(params->request); if (ret) - goto error; + return ret; WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<id), "%s didn't clear reload\n", ring->name); @@ -1279,22 +1208,19 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, case I915_EXEC_CONSTANTS_REL_SURFACE: if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) { DRM_DEBUG("non-0 rel constants mode on non-RCS\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } if (instp_mode != dev_priv->relative_constants_mode) { if (INTEL_INFO(dev)->gen < 4) { DRM_DEBUG("no rel constants on pre-gen4\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } if (INTEL_INFO(dev)->gen > 5 && instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) { DRM_DEBUG("rel surface constants mode invalid on gen5+\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } /* The HW changed the meaning on this bit on gen6 */ @@ -1304,15 +1230,14 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, break; default: DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode); - ret = -EINVAL; - goto error; + return -EINVAL; } if (ring == &dev_priv->ring[RCS] && - instp_mode != dev_priv->relative_constants_mode) { + instp_mode != dev_priv->relative_constants_mode) { ret = intel_ring_begin(params->request, 4); if (ret) - goto error; + return ret; intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); @@ -1326,42 +1251,25 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (args->flags & I915_EXEC_GEN7_SOL_RESET) { ret = i915_reset_gen7_sol_offsets(dev, params->request); if (ret) - goto error; + return ret; } exec_len = args->batch_len; exec_start = params->batch_obj_vm_offset + params->args_batch_start_offset; - if (cliprects) { - for (i = 0; i < args->num_cliprects; i++) { - ret = i915_emit_box(params->request, &cliprects[i], - args->DR1, args->DR4); - if (ret) - goto error; - - ret = ring->dispatch_execbuffer(params->request, - exec_start, exec_len, - params->dispatch_flags); - if (ret) - goto error; - } - } else { - ret = ring->dispatch_execbuffer(params->request, - exec_start, exec_len, - params->dispatch_flags); - if (ret) - return ret; - } + ret = ring->dispatch_execbuffer(params->request, + exec_start, exec_len, + params->dispatch_flags); + if (ret) + return ret; trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, params->request); i915_gem_execbuffer_retire_commands(params); -error: - kfree(cliprects); - return ret; + return 0; } /** diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 256167b2e2ab..1bb1c9c8126e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -902,21 +902,6 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, return -EINVAL; } - if (args->num_cliprects != 0) { - DRM_DEBUG("clip rectangles are only valid on pre-gen5\n"); - return -EINVAL; - } else { - if (args->DR4 == 0xffffffff) { - DRM_DEBUG("UXA submitting garbage DR4, fixing up\n"); - args->DR4 = 0; - } - - if (args->DR1 || args->DR4 || args->cliprects_ptr) { - DRM_DEBUG("0 cliprects but dirt in cliprects fields\n"); - return -EINVAL; - } - } - if (args->flags & I915_EXEC_GEN7_SOL_RESET) { DRM_DEBUG("sol reset is gen7 only\n"); return -EINVAL; From 26148bd3c0f1fbd8f2b0dae994f3195316f677db Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Fri, 18 Sep 2015 23:39:51 +0530 Subject: [PATCH 115/134] drm/i915/bxt: Set time interval unit to 0.833us Note that in Bspec you have to dig around in a section called "Timestamp bases" and Bspec update request is filed. Signed-off-by: Ankitprasad Sharma Signed-off-by: Akash Goel Signed-off-by: Sagar Arun Kamble Reviewed-by: Imre Deak [danvet: Add note about state of Bspec.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 07588b63d434..6be853d2233c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2840,8 +2840,11 @@ enum skl_disp_power_wells { #define INTERVAL_1_28_US(us) (((us) * 100) >> 7) #define INTERVAL_1_33_US(us) (((us) * 3) >> 2) +#define INTERVAL_0_833_US(us) (((us) * 6) / 5) #define GT_INTERVAL_FROM_US(dev_priv, us) (IS_GEN9(dev_priv) ? \ - INTERVAL_1_33_US(us) : \ + (IS_BROXTON(dev_priv) ? \ + INTERVAL_0_833_US(us) : \ + INTERVAL_1_33_US(us)) : \ INTERVAL_1_28_US(us)) /* From d39398f5374e2ae35832ad8e01e60e8deb6d4e1c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Oct 2015 11:17:44 +0300 Subject: [PATCH 116/134] drm/i915/snb: remove pre-production hardware workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 52642aff1dab..1e67484fd5dc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4558,22 +4558,6 @@ void i915_gem_init_swizzling(struct drm_device *dev) BUG(); } -static bool -intel_enable_blt(struct drm_device *dev) -{ - if (!HAS_BLT(dev)) - return false; - - /* The blitter was dysfunctional on early prototypes */ - if (IS_GEN6(dev) && dev->pdev->revision < 8) { - DRM_INFO("BLT not supported on this pre-production hardware;" - " graphics performance will be degraded.\n"); - return false; - } - - return true; -} - static void init_unused_ring(struct drm_device *dev, u32 base) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4616,7 +4600,7 @@ int i915_gem_init_rings(struct drm_device *dev) goto cleanup_render_ring; } - if (intel_enable_blt(dev)) { + if (HAS_BLT(dev)) { ret = intel_init_blt_ring_buffer(dev); if (ret) goto cleanup_bsd_ring; From 5b5929cbe3f77e1a01cd2709c8dd7fe0302af1b6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 7 Oct 2015 11:17:46 +0300 Subject: [PATCH 117/134] drm/i915/chv: remove pre-production hardware workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä [danvet: Appease gcc and remove the unused variable.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 56 +++++++++++++-------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 60d120c472ab..3f9b3c078223 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5061,32 +5061,27 @@ static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; u32 val, rp0; - if (dev->pdev->revision >= 0x20) { - val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE); + val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE); - switch (INTEL_INFO(dev)->eu_total) { - case 8: - /* (2 * 4) config */ - rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT); - break; - case 12: - /* (2 * 6) config */ - rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT); - break; - case 16: - /* (2 * 8) config */ - default: - /* Setting (2 * 8) Min RP0 for any other combination */ - rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT); - break; - } - rp0 = (rp0 & FB_GFX_FREQ_FUSE_MASK); - } else { - /* For pre-production hardware */ - val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG); - rp0 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) & - PUNIT_GPU_STATUS_MAX_FREQ_MASK; + switch (INTEL_INFO(dev)->eu_total) { + case 8: + /* (2 * 4) config */ + rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT); + break; + case 12: + /* (2 * 6) config */ + rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT); + break; + case 16: + /* (2 * 8) config */ + default: + /* Setting (2 * 8) Min RP0 for any other combination */ + rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT); + break; } + + rp0 = (rp0 & FB_GFX_FREQ_FUSE_MASK); + return rp0; } @@ -5102,18 +5097,11 @@ static int cherryview_rps_rpe_freq(struct drm_i915_private *dev_priv) static int cherryview_rps_guar_freq(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; u32 val, rp1; - if (dev->pdev->revision >= 0x20) { - val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE); - rp1 = (val & FB_GFX_FREQ_FUSE_MASK); - } else { - /* For pre-production hardware */ - val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - rp1 = ((val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) & - PUNIT_GPU_STATUS_MAX_FREQ_MASK); - } + val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE); + rp1 = (val & FB_GFX_FREQ_FUSE_MASK); + return rp1; } From 6a8aadc43974729349cb6b823d774c091afd78cd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 1 Oct 2015 18:06:50 +0200 Subject: [PATCH 118/134] drm/i915: Resurrect golden context on gen6/7 In commit 8f0e2b9d95a88ca5d8349deef2375644faf184ae Author: Daniel Vetter Date: Tue Dec 2 16:19:07 2014 +0100 drm/i915: Move golden context init into ->init_context I've shuffled around per-ctx init code a bit for legacy contexts but accidentally dropped the render state init call on gen6/7. Resurrect it. Reported-by: Francisco Jerez Cc: Francisco Jerez Cc: Dave Gordon Cc: Thomas Daniel Signed-off-by: Daniel Vetter Reviewed-by: Francisco Jerez Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c82c74caa73c..9035f8c7a8a7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2623,6 +2623,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) GEN8_RING_SEMAPHORE_INIT; } } else if (INTEL_INFO(dev)->gen >= 6) { + ring->init_context = i915_gem_render_state_init; ring->add_request = gen6_add_request; ring->flush = gen7_render_ring_flush; if (INTEL_INFO(dev)->gen == 6) From 02235808b61cd9382d224b0df263193006dd9913 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 7 Oct 2015 14:44:01 +0300 Subject: [PATCH 119/134] drm/i915: Don't warn if the workaround list is empty. It's not an error for the workaround list to be empty if no workarounds are needed. This will avoid spamming the logs unnecessarily on Gen6 after the workaround list is hooked up on pre-Gen8 hardware by the following commits. Signed-off-by: Francisco Jerez Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9035f8c7a8a7..702d3a2d73b9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -717,7 +717,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; - if (WARN_ON_ONCE(w->count == 0)) + if (w->count == 0) return 0; ring->gpu_caches_dirty = true; From 4f91fc6d2c1d98b3da7a8341ef5ec66ccf2916b9 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 7 Oct 2015 14:44:02 +0300 Subject: [PATCH 120/134] drm/i915: Hook up ring workaround writes at context creation time on Gen6-7. intel_rcs_ctx_init() emits all workaround register writes on the list to the ring, in addition to calling i915_gem_render_state_init(). The workaround list is currently empty on Gen6-7 so this shouldn't cause any functional changes. Signed-off-by: Francisco Jerez Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 702d3a2d73b9..654ae991ea13 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2623,7 +2623,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) GEN8_RING_SEMAPHORE_INIT; } } else if (INTEL_INFO(dev)->gen >= 6) { - ring->init_context = i915_gem_render_state_init; + ring->init_context = intel_rcs_ctx_init; ring->add_request = gen6_add_request; ring->flush = gen7_render_ring_flush; if (INTEL_INFO(dev)->gen == 6) From 468f9d2903bcf23e50663679eab5a18da5b886f6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 8 Oct 2015 09:54:44 +0200 Subject: [PATCH 121/134] drm/i915/irq: Fix kernel-doc warnings Add the dev parameter for the functions i915_enable_asle_pipestat() and i915_reset_and_wakeup() to the kernel-doc to fix the following warnings: .//drivers/gpu/drm/i915/i915_irq.c:586: warning: No description found for parameter 'dev' .//drivers/gpu/drm/i915/i915_irq.c:2400: warning: No description found for parameter 'dev' Signed-off-by: Javier Martinez Canillas Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 76bd40e13391..18b475429e18 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -581,6 +581,7 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, /** * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion + * @dev: drm device */ static void i915_enable_asle_pipestat(struct drm_device *dev) { @@ -2392,6 +2393,7 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv, /** * i915_reset_and_wakeup - do process context error handling work + * @dev: drm device * * Fire an error uevent so userspace can see that a hang or error * was detected. From aafd858192bc98fab9230f6a634af85c4079f80f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 8 Oct 2015 09:57:49 +0200 Subject: [PATCH 122/134] drm/i915/irq: Fix misspelled word register in kernel-doc There is a typo in the function i915_handle_error() kernel-doc and the word register is spelled wrongly. Signed-off-by: Javier Martinez Canillas Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 18b475429e18..bd56ca629b31 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2571,7 +2571,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) * i915_handle_error - handle a gpu error * @dev: drm device * - * Do some basic checking of regsiter state at error time and + * Do some basic checking of register state at error time and * dump it to the syslog. Also call i915_capture_error_state() to make * sure we get a record and make it available in debugfs. Fire a uevent * so userspace knows something bad happened (should trigger collection From 11aee0f6d1b6520620c5e7af04504ce9de588520 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 8 Oct 2015 19:27:59 +0530 Subject: [PATCH 123/134] drm/i915: use error path Use goto to handle the error path to avoid duplicating the same code. In the error path intel_dig_port is the last one to be released as it was the first one to be allocated and ideally the error path should be the reverse of the execution path. Cc: Daniel Vetter Cc: Jani Nikula Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8d34ca7b287a..18bcfbe0b8ba 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6168,10 +6168,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) return; intel_connector = intel_connector_alloc(); - if (!intel_connector) { - kfree(intel_dig_port); - return; - } + if (!intel_connector) + goto err_connector_alloc; intel_encoder = &intel_dig_port->base; encoder = &intel_encoder->base; @@ -6219,11 +6217,18 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; dev_priv->hotplug.irq_port[port] = intel_dig_port; - if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { - drm_encoder_cleanup(encoder); - kfree(intel_dig_port); - kfree(intel_connector); - } + if (!intel_dp_init_connector(intel_dig_port, intel_connector)) + goto err_init_connector; + + return; + +err_init_connector: + drm_encoder_cleanup(encoder); + kfree(intel_connector); +err_connector_alloc: + kfree(intel_dig_port); + + return; } void intel_dp_mst_suspend(struct drm_device *dev) From 8166fcead6b29589f264b9d900c0770f501964c3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 8 Oct 2015 21:50:57 +0200 Subject: [PATCH 124/134] Revert "drm/i915: Add hot_plug hook for hdmi encoder" This reverts commit 0b5e88dc25ee6c9040c0355e6e025dcbc9c8de92. It completely breaks booting on at least bsw (and maybe more). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=88081 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 54 +++++++------------------------ 1 file changed, 11 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 03d85909c6ab..3b28ed3237d3 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1369,16 +1369,18 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force) return connected; } -static void intel_hdmi_hot_plug(struct intel_encoder *intel_encoder) +static enum drm_connector_status +intel_hdmi_detect(struct drm_connector *connector, bool force) { - struct intel_hdmi *intel_hdmi = - enc_to_intel_hdmi(&intel_encoder->base); - struct intel_connector *intel_connector = - intel_hdmi->attached_connector; - struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); + enum drm_connector_status status; + struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct drm_i915_private *dev_priv = to_i915(connector->dev); bool live_status = false; unsigned int retry = 3; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, connector->name); + while (!live_status && --retry) { live_status = intel_digital_port_connected(dev_priv, hdmi_to_dig_port(intel_hdmi)); @@ -1388,48 +1390,15 @@ static void intel_hdmi_hot_plug(struct intel_encoder *intel_encoder) if (!live_status) DRM_DEBUG_KMS("Live status not up!"); - /* - * We are here, means there is a hotplug or a force - * detection. Clear the cached EDID and probe the - * DDC bus to check the current status of HDMI. - */ - intel_hdmi_unset_edid(&intel_connector->base); - if (intel_hdmi_set_edid(&intel_connector->base, live_status)) - DRM_DEBUG_DRIVER("DDC probe: got EDID\n"); - else - DRM_DEBUG_DRIVER("DDC probe: no EDID\n"); -} + intel_hdmi_unset_edid(connector); -static enum drm_connector_status -intel_hdmi_detect(struct drm_connector *connector, bool force) -{ - enum drm_connector_status status; - struct intel_connector *intel_connector = - to_intel_connector(connector); - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", - connector->base.id, connector->name); - - /* - * There are many userspace calls which probe EDID from - * detect path. In case of multiple hotplug/unplug, these - * can cause race conditions while probing EDID. Also its - * waste of CPU cycles to read the EDID again and again - * unless there is a real hotplug. - * So, rely on hotplugs and init to read edid. - * Check connector status based on availability of cached EDID. - */ - - if (intel_connector->detect_edid) { + if (intel_hdmi_set_edid(connector, live_status)) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; status = connector_status_connected; - DRM_DEBUG_DRIVER("hdmi status = connected\n"); - } else { + } else status = connector_status_disconnected; - DRM_DEBUG_DRIVER("hdmi status = disconnected\n"); - } return status; } @@ -2145,7 +2114,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_connector->unregister = intel_connector_unregister; intel_hdmi_add_properties(intel_hdmi, connector); - intel_encoder->hot_plug = intel_hdmi_hot_plug; intel_connector_attach_encoder(intel_connector, intel_encoder); drm_connector_register(connector); From 3a2fb2c394ff0f0ea90bacc557147d9ac733d13c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 8 Oct 2015 21:51:57 +0200 Subject: [PATCH 125/134] Revert "drm/i915: Call encoder hotplug for init and resume cases" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5d250b05918c002b63632c7db91c3c5f924c6a3b. It results on a deadlock on platforms where we need to (at least partially) re-init hpd interrupts from power domain code, since ->hot_plug might again grab a power well reference (to do edid/dp_aux transactions. At least chv is affected. Reported-by: Ville Syrjälä References: http://mid.gmane.org/20151008133548.GX26517@intel.com Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hotplug.c | 11 ----------- drivers/gpu/drm/i915/intel_sdvo.c | 1 + 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index eac47571e409..53c0173a39fe 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -458,7 +458,6 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *encoder; struct drm_connector *connector; int i; @@ -483,16 +482,6 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); spin_unlock_irq(&dev_priv->irq_lock); - - /* - * Connected boot / resume scenarios can't generate new hot plug. - * So, probe it manually. - */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { - if (encoder->hot_plug) - encoder->hot_plug(encoder); - } } void intel_hpd_init_work(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 853f4b2f50db..c42b636c2087 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2460,6 +2460,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) * Ensure that they get re-enabled when an interrupt happens. */ intel_encoder->hot_plug = intel_sdvo_enable_hotplug; + intel_sdvo_enable_hotplug(intel_encoder); } else { intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; } From 3badb49f08f66fbdbf9da8335c5db4b05a1677c8 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 23 Sep 2015 12:52:23 -0300 Subject: [PATCH 126/134] drm/i915: don't allocate fbcon from stolen memory if it's too big Technology has evolved and now we have eDP panels with 3200x1800 resolution. In the meantime, the BIOS guys didn't change the default 32mb for stolen memory. On top of that, we can't assume our users will be able to increase the default stolen memory size to more than 32mb - I'm not even sure all BIOSes allow that. So just the fbcon buffer alone eats 22mb of my stolen memroy, and due to the BDW/SKL restriction of not using the last 8mb of stolen memory, all that's left for FBC is 2mb! Since fbcon is not the coolest feature ever, I think it's better to save our precious stolen resource to FBC and the other guys. On the other hand, we really want to use as much stolen memory as possible, since on some older systems the stolen memory may be a considerable percentage of the total available memory. This patch tries to achieve a little balance using a simple heuristic: if the fbcon wants more than half of the available stolen memory, don't use stolen memory in order to leave some for FBC and the other features. The long term plan should be to implement a way to set priorities for stolen memory allocation and then evict low priority users when the high priority ones need the memory. While we still don't have that, let's try to make FBC usable with the simple solution. Cc: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++++ drivers/gpu/drm/i915/intel_fbdev.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 539c3737e823..184ba09842f5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2545,6 +2545,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config) { struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_gem_object *obj = NULL; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct drm_framebuffer *fb = &plane_config->fb->base; @@ -2557,6 +2558,12 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, if (plane_config->size == 0) return false; + /* If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. */ + if (size_aligned * 2 > dev_priv->gtt.stolen_usable_size) + return false; + obj = i915_gem_object_create_stolen_for_preallocated(dev, base_aligned, base_aligned, diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 65329127f0b9..4fd5fdfef6bd 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -121,8 +121,9 @@ static int intelfb_alloc(struct drm_fb_helper *helper, container_of(helper, struct intel_fbdev, helper); struct drm_framebuffer *fb; struct drm_device *dev = helper->dev; + struct drm_i915_private *dev_priv = to_i915(dev); struct drm_mode_fb_cmd2 mode_cmd = {}; - struct drm_i915_gem_object *obj; + struct drm_i915_gem_object *obj = NULL; int size, ret; /* we don't do packed 24bpp */ @@ -139,7 +140,12 @@ static int intelfb_alloc(struct drm_fb_helper *helper, size = mode_cmd.pitches[0] * mode_cmd.height; size = PAGE_ALIGN(size); - obj = i915_gem_object_create_stolen(dev, size); + + /* If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. */ + if (size * 2 < dev_priv->gtt.stolen_usable_size) + obj = i915_gem_object_create_stolen(dev, size); if (obj == NULL) obj = i915_gem_alloc_object(dev, size); if (!obj) { From a42e5a23ed1939a8eca5a753c19bb8b0e5cee475 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 30 Sep 2015 17:05:43 -0300 Subject: [PATCH 127/134] drm/i915: remove pre-atomic check from SKL update_primary_plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comment suggests the check was there for some non-fully-atomic case, and I couldn't find a case where we wouldn't correctly initialize plane_state, so remove the check. Let's leave a WARN there just in case. Signed-off-by: Paulo Zanoni Acked-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 32 +++++++++++----------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 184ba09842f5..6b3b65e3b36b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3131,27 +3131,19 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, fb->pixel_format); surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0); - /* - * FIXME: intel_plane_state->src, dst aren't set when transitional - * update_plane helpers are called from legacy paths. - * Once full atomic crtc is available, below check can be avoided. - */ - if (drm_rect_width(&plane_state->src)) { - scaler_id = plane_state->scaler_id; - src_x = plane_state->src.x1 >> 16; - src_y = plane_state->src.y1 >> 16; - src_w = drm_rect_width(&plane_state->src) >> 16; - src_h = drm_rect_height(&plane_state->src) >> 16; - dst_x = plane_state->dst.x1; - dst_y = plane_state->dst.y1; - dst_w = drm_rect_width(&plane_state->dst); - dst_h = drm_rect_height(&plane_state->dst); + WARN_ON(drm_rect_width(&plane_state->src) == 0); - WARN_ON(x != src_x || y != src_y); - } else { - src_w = intel_crtc->config->pipe_src_w; - src_h = intel_crtc->config->pipe_src_h; - } + scaler_id = plane_state->scaler_id; + src_x = plane_state->src.x1 >> 16; + src_y = plane_state->src.y1 >> 16; + src_w = drm_rect_width(&plane_state->src) >> 16; + src_h = drm_rect_height(&plane_state->src) >> 16; + dst_x = plane_state->dst.x1; + dst_y = plane_state->dst.y1; + dst_w = drm_rect_width(&plane_state->dst); + dst_h = drm_rect_height(&plane_state->dst); + + WARN_ON(x != src_x || y != src_y); if (intel_rotation_90_or_270(rotation)) { /* stride = Surface height in tiles */ From c4ffd40908c30a33291227920e921f6b45b9e8f7 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 1 Oct 2015 19:55:57 -0300 Subject: [PATCH 128/134] drm/i915: fix CFB size calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were considering the whole framebuffer height, but the spec says we should only consider the active display height size. There were still some unclear questions based on the spec, but the hardware guys clarified them for us. According to them: - CFB size = CFB stride * Number of lines FBC writes to CFB - CFB stride = plane stride / compression limit - Number of lines FBC writes to CFB = MIN(plane source height, maximum number of lines FBC writes to CFB) - Plane source height = - pipe source height (PIPE_SRCSZ register) (before SKL) - plane size register height (PLANE_SIZE register) (SKL+) - Maximum number of lines FBC writes to CFB = - plane source height (before HSW) - 2048 (HSW+) For the plane source height, I could just have made our code do I915_READ() in order to be more future proof, but since it's not cool to do register reads I decided to just recalculate the values we use when we actually write to those registers. With this patch, depending on your machine configuration, a lot of the kms_frontbuffer_tracking subtests that used to result in a SKIP due to not enough stolen memory still start resulting in a PASS. v2: Use the clipped src size instead of pipe_src_h (Ville). v3: Use the appropriate information provided by the hardware guys. v4: Bikesheds: s/sizes/size/, s/fb_cpp/cpp/ (Ville). v5: - Don't use crtc->config->pipe_src_x for BDW- (Ville). - Fix the register name written in the comment. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 54 +++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 1b2ebb2c1f53..18e228bdf493 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -698,16 +698,61 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->fbc.lock); } -static int intel_fbc_setup_cfb(struct drm_i915_private *dev_priv, int size, - int fb_cpp) +/* + * For SKL+, the plane source size used by the hardware is based on the value we + * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value + * we wrote to PIPESRC. + */ +static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc, + int *width, int *height) { + struct intel_plane_state *plane_state = + to_intel_plane_state(crtc->base.primary->state); + int w, h; + + if (intel_rotation_90_or_270(plane_state->base.rotation)) { + w = drm_rect_height(&plane_state->src) >> 16; + h = drm_rect_width(&plane_state->src) >> 16; + } else { + w = drm_rect_width(&plane_state->src) >> 16; + h = drm_rect_height(&plane_state->src) >> 16; + } + + if (width) + *width = w; + if (height) + *height = h; +} + +static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; + int lines; + + intel_fbc_get_plane_source_size(crtc, NULL, &lines); + if (INTEL_INFO(dev_priv)->gen >= 7) + lines = min(lines, 2048); + + return lines * fb->pitches[0]; +} + +static int intel_fbc_setup_cfb(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; + int size, cpp; + + size = intel_fbc_calculate_cfb_size(crtc); + cpp = drm_format_plane_cpp(fb->pixel_format, 0); + if (size <= dev_priv->fbc.uncompressed_size) return 0; /* Release any current block */ __intel_fbc_cleanup_cfb(dev_priv); - return intel_fbc_alloc_cfb(dev_priv, size, fb_cpp); + return intel_fbc_alloc_cfb(dev_priv, size, cpp); } static bool stride_is_valid(struct drm_i915_private *dev_priv, @@ -897,8 +942,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) goto out_disable; } - if (intel_fbc_setup_cfb(dev_priv, obj->base.size, - drm_format_plane_cpp(fb->pixel_format, 0))) { + if (intel_fbc_setup_cfb(intel_crtc)) { set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; } From 856312aeb124b0477d452aa43415711109b46cbe Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 1 Oct 2015 19:57:12 -0300 Subject: [PATCH 129/134] drm/i915: fix FBC buffer size checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to my experiments (and later confirmation from the hardware developers), the maximum sizes mentioned in the specification delimit how far in the buffer the hardware tracking can go. And the hardware calculates the size based on the plane address we provide - and the provided plane address might not be the real x:0,y:0 point due to the compute_page_offset() function. On platforms that do the x/y offset adjustment trick it will be really hard to reproduce a bug, but on the current SKL we can reproduce the bug with igt/kms_frontbuffer_tracking/fbc-farfromfence. With this patch, we'll go from "CRC assertion failure" to "FBC unexpectedly disabled", which is still a failure on the test suite but is not a perceived user bug - you will just not save as much power as you could if FBC is disabled. v2, rewrite patch after clarification from the Hadware guys: - Rename function so it's clear what the check is for. - Use the new intel_fbc_get_plane_source_sizes() function in order to get the proper sizes as seen by FBC. v3: - Rebase after the s/sizes/size/ on the previous patch. - Adjust comment wording (Ville). - s/used_/effective_/ (Ville). Testcase: igt/kms_frontbuffer_tracking/fbc-farfromfence (SKL) Reviewed-by: Ville Syrjälä Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 18e228bdf493..cf47352b7b8e 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -799,10 +799,16 @@ static bool pixel_format_is_valid(struct drm_framebuffer *fb) } } -static bool pipe_size_is_valid(struct intel_crtc *crtc) +/* + * For some reason, the hardware tracking starts looking at whatever we + * programmed as the display plane base address register. It does not look at + * the X and Y offset registers. That's why we look at the crtc->adjusted{x,y} + * variables instead of just looking at the pipe/plane size. + */ +static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - unsigned int max_w, max_h; + unsigned int effective_w, effective_h, max_w, max_h; if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { max_w = 4096; @@ -815,8 +821,11 @@ static bool pipe_size_is_valid(struct intel_crtc *crtc) max_h = 1536; } - return crtc->config->pipe_src_w <= max_w && - crtc->config->pipe_src_h <= max_h; + intel_fbc_get_plane_source_size(crtc, &effective_w, &effective_h); + effective_w += crtc->adjusted_x; + effective_h += crtc->adjusted_y; + + return effective_w <= max_w && effective_h <= max_h; } /** @@ -893,7 +902,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) goto out_disable; } - if (!pipe_size_is_valid(intel_crtc)) { + if (!intel_fbc_hw_tracking_covers_screen(intel_crtc)) { set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); goto out_disable; } From 0ad98c74e093041eb163b01013eb46989f2124aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 8 Oct 2015 12:08:20 +0300 Subject: [PATCH 130/134] drm/i915: Determine the stolen memory base address on gen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There isn't an explicit stolen memory base register on gen2. Some old comment in the i915 code suggests we should get it via max_low_pfn_mapped, but that's clearly a bad idea on my MGM. The e820 map in said machine looks like this: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009f7ff] usable [ 0.000000] BIOS-e820: [mem 0x000000000009f800-0x000000000009ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000000ce000-0x00000000000cffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000001f6effff] usable [ 0.000000] BIOS-e820: [mem 0x000000001f6f0000-0x000000001f6f7fff] ACPI data [ 0.000000] BIOS-e820: [mem 0x000000001f6f8000-0x000000001f6fffff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x000000001f700000-0x000000001fffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fec10000-0x00000000fec1ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000ffb00000-0x00000000ffbfffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fff00000-0x00000000ffffffff] reserved That makes max_low_pfn_mapped = 1f6f0000, so assuming our stolen memory would start there would place it on top of some ACPI memory regions. So not a good idea as already stated. The 9MB region after the ACPI regions at 0x1f700000 however looks promising given that the macine reports the stolen memory size to be 8MB. Looking at the PGTBL_CTL register, the GTT entries are at offset 0x1fee00000, and given that the GTT entries occupy 128KB, it looks like the stolen memory could start at 0x1f700000 and the GTT entries would occupy the last 128KB of the stolen memory. After some more digging through chipset documentation, I've determined the BIOS first allocates space for something called TSEG (something to do with SMM) from the top of memory, and then it allocates the graphics stolen memory below that. Accordind to the chipset documentation TSEG has a fixed size of 1MB on 855. So that explains the top 1MB in the e820 region. And it also confirms that the GTT entries are in fact at the end of the the stolen memory region. Derive the stolen memory base address on gen2 the same as the BIOS does (TOM-TSEG_SIZE-stolen_size). There are a few differences between the registers on various gen2 chipsets, so a few different codepaths are required. 865G is again bit more special since it seems to support enough memory to hit 4GB address space issues. This means the PCI allocations will also affect the location of the stolen memory. Fortunately there appears to be the TOUD register which may give us the correct answer directly. But the chipset docs are a bit unclear, so I'm not 100% sure that the graphics stolen memory is always the last thing the BIOS steals. Someone would need to verify it on a real system. I tested this on the my 830 and 855 machines, and so far everything looks peachy. v2: Rewrite to use the TOM-TSEG_SIZE-stolen_size and TOUD methods v3: Fix TSEG size for 830 v4: Add missing 'else' (Chris) Tested-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 92 +++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 69eebc678f01..cdacf3f5b77a 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -30,6 +30,9 @@ #include #include "i915_drv.h" +#define KB(x) ((x) * 1024) +#define MB(x) (KB(x) * 1024) + /* * The BIOS typically reserves some of the system's memory for the exclusive * use of the integrated graphics. This memory is no longer available for @@ -91,24 +94,91 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) /* Almost universally we can find the Graphics Base of Stolen Memory * at offset 0x5c in the igfx configuration space. On a few (desktop) * machines this is also mirrored in the bridge device at different - * locations, or in the MCHBAR. On gen2, the layout is again slightly - * different with the Graphics Segment immediately following Top of - * Memory (or Top of Usable DRAM). Note it appears that TOUD is only - * reported by 865g, so we just use the top of memory as determined - * by the e820 probe. + * locations, or in the MCHBAR. + * + * On 865 we just check the TOUD register. + * + * On 830/845/85x the stolen memory base isn't available in any + * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size. * - * XXX However gen2 requires an unavailable symbol. */ base = 0; if (INTEL_INFO(dev)->gen >= 3) { /* Read Graphics Base of Stolen Memory directly */ pci_read_config_dword(dev->pdev, 0x5c, &base); base &= ~((1<<20) - 1); - } else { /* GEN2 */ -#if 0 - /* Stolen is immediately above Top of Memory */ - base = max_low_pfn_mapped << PAGE_SHIFT; -#endif + } else if (IS_I865G(dev)) { + u16 toud = 0; + + /* + * FIXME is the graphics stolen memory region + * always at TOUD? Ie. is it always the last + * one to be allocated by the BIOS? + */ + pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0), + I865_TOUD, &toud); + + base = toud << 16; + } else if (IS_I85X(dev)) { + u32 tseg_size = 0; + u32 tom; + u8 tmp; + + pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), + I85X_ESMRAMC, &tmp); + + if (tmp & TSEG_ENABLE) + tseg_size = MB(1); + + pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1), + I85X_DRB3, &tmp); + tom = tmp * MB(32); + + base = tom - tseg_size - dev_priv->gtt.stolen_size; + } else if (IS_845G(dev)) { + u32 tseg_size = 0; + u32 tom; + u8 tmp; + + pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), + I845_ESMRAMC, &tmp); + + if (tmp & TSEG_ENABLE) { + switch (tmp & I845_TSEG_SIZE_MASK) { + case I845_TSEG_SIZE_512K: + tseg_size = KB(512); + break; + case I845_TSEG_SIZE_1M: + tseg_size = MB(1); + break; + } + } + + pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), + I830_DRB3, &tmp); + tom = tmp * MB(32); + + base = tom - tseg_size - dev_priv->gtt.stolen_size; + } else if (IS_I830(dev)) { + u32 tseg_size = 0; + u32 tom; + u8 tmp; + + pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), + I830_ESMRAMC, &tmp); + + if (tmp & TSEG_ENABLE) { + if (tmp & I830_TSEG_SIZE_1M) + tseg_size = MB(1); + else + tseg_size = KB(512); + } + + pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0), + I830_DRB3, &tmp); + tom = tmp * MB(32); + + base = tom - tseg_size - dev_priv->gtt.stolen_size; } if (base == 0) From 61fb58815192c558d74016721dae6235c18c0fbf Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 8 Oct 2015 15:37:00 +0100 Subject: [PATCH 131/134] drm/i915: Remove wrong warning from i915_gem_context_clean commit e9f24d5fb7cf3628b195b18ff3ac4e37937ceeae Author: Tvrtko Ursulin Date: Mon Oct 5 13:26:36 2015 +0100 drm/i915: Clean up associated VMAs on context destruction Introduced a wrong assumption that all contexts have a ppgtt instance. This is not true when full PPGTT is not active so remove the WARN_ON_ONCE from the context cleanup code. Signed-off-by: Tvrtko Ursulin Cc: Michel Thierry Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 680b4c9f6b73..8c688a5f1589 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -138,7 +138,7 @@ static void i915_gem_context_clean(struct intel_context *ctx) struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; struct i915_vma *vma, *next; - if (WARN_ON_ONCE(!ppgtt)) + if (!ppgtt) return; WARN_ON(!list_empty(&ppgtt->base.active_list)); From 381e8ae377d9f0708a5073cb6ee2fa24ef303623 Mon Sep 17 00:00:00 2001 From: Tomas Elf Date: Thu, 8 Oct 2015 19:31:33 +0100 Subject: [PATCH 132/134] drm/i915: Early exit from semaphore_waits_for for execlist mode. When submitting semaphores in execlist mode the hang checker crashes in this function because it is only runnable in ring submission mode. The reason this is of particular interest to the TDR patch series is because we use semaphores as a mean to induce hangs during testing (which is the recommended way to induce hangs for gen8+). It's not clear how this is supposed to work in execlist mode since: 1. This function requires a ring buffer. 2. Retrieving a ring buffer in execlist mode requires us to retrieve the corresponding context, which we get from a request. 3. Retieving a request from the hang checker is not straight-forward since that requires us to grab the struct_mutex in order to synchronize against the request retirement thread. 4. Grabbing the struct_mutex from the hang checker is nothing that we will do since that puts us at risk of deadlock since a hung thread might be holding the struct_mutex already. Therefore it's not obvious how we're supposed to deal with this. For now, we're doing an early exit from this function, which avoids any kernel panic situation when running our own internal TDR ULT. * v2: (Chris Wilson) Turned the execlist mode check into a ringbuffer NULL check to make it more submission mode agnostic and less of a layering violation. Signed-off-by: Tomas Elf Cc: Chris Wilson Cc: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bd56ca629b31..637c13211613 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2784,6 +2784,26 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno) u64 offset = 0; int i, backwards; + /* + * This function does not support execlist mode - any attempt to + * proceed further into this function will result in a kernel panic + * when dereferencing ring->buffer, which is not set up in execlist + * mode. + * + * The correct way of doing it would be to derive the currently + * executing ring buffer from the current context, which is derived + * from the currently running request. Unfortunately, to get the + * current request we would have to grab the struct_mutex before doing + * anything else, which would be ill-advised since some other thread + * might have grabbed it already and managed to hang itself, causing + * the hang checker to deadlock. + * + * Therefore, this function does not support execlist mode in its + * current form. Just return NULL and move on. + */ + if (ring->buffer == NULL) + return NULL; + ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); if (!ipehr_is_semaphore_wait(ring->dev, ipehr)) return NULL; From 261a27d11fa1dec47c47ece6968eaaba55861eca Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 8 Oct 2015 15:28:25 -0700 Subject: [PATCH 133/134] drm/i915: Partial revert of atomic watermark series It's been reported that the atomic watermark series triggers some regressions on SKL, which we haven't been able to track down yet. Let's temporarily revert these patches while we track down the root cause. This commit squashes the reverts of: 76305b1 drm/i915: Calculate watermark configuration during atomic check (v2) a4611e4 drm/i915: Don't set plane visible during HW readout if CRTC is off a28170f drm/i915: Calculate ILK-style watermarks during atomic check (v3) de4a9f8 drm/i915: Calculate pipe watermarks into CRTC state (v3) de165e0 drm/i915: Refactor ilk_update_wm (v3) Reference: http://lists.freedesktop.org/archives/intel-gfx/2015-October/077190.html Cc: "Zanoni, Paulo R" Cc: "Vetter, Daniel" Signed-off-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 -- drivers/gpu/drm/i915/intel_display.c | 60 +------ drivers/gpu/drm/i915/intel_drv.h | 49 +++--- drivers/gpu/drm/i915/intel_pm.c | 234 +++++++++++++++------------ 4 files changed, 152 insertions(+), 203 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b39b5cc0c096..4feec193ff33 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -627,8 +627,6 @@ struct drm_i915_display_funcs { int target, int refclk, struct dpll *match_clock, struct dpll *best_clock); - int (*compute_pipe_wm)(struct intel_crtc *crtc, - struct drm_atomic_state *state); void (*update_wm)(struct drm_crtc *crtc); int (*modeset_calc_cdclk)(struct drm_atomic_state *state); void (*modeset_commit_cdclk)(struct drm_atomic_state *state); @@ -1692,13 +1690,6 @@ struct i915_execbuffer_params { struct drm_i915_gem_request *request; }; -/* used in computing the new watermarks state */ -struct intel_wm_config { - unsigned int num_pipes_active; - bool sprites_enabled; - bool sprites_scaled; -}; - struct drm_i915_private { struct drm_device *dev; struct kmem_cache *objects; @@ -1924,9 +1915,6 @@ struct drm_i915_private { */ uint16_t skl_latency[8]; - /* Committed wm config */ - struct intel_wm_config config; - /* * The skl_wm_values structure is a bit too big for stack * allocation, so we keep the staging struct where we store diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6b3b65e3b36b..cddb0c692334 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11836,12 +11836,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } ret = 0; - if (dev_priv->display.compute_pipe_wm) { - ret = dev_priv->display.compute_pipe_wm(intel_crtc, state); - if (ret) - return ret; - } - if (INTEL_INFO(dev)->gen >= 9) { if (mode_changed) ret = skl_update_scaler_crtc(pipe_config); @@ -13047,45 +13041,6 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return 0; } -/* - * Handle calculation of various watermark data at the end of the atomic check - * phase. The code here should be run after the per-crtc and per-plane 'check' - * handlers to ensure that all derived state has been updated. - */ -static void calc_watermark_data(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - struct drm_crtc *crtc; - struct drm_crtc_state *cstate; - struct drm_plane *plane; - struct drm_plane_state *pstate; - - /* - * Calculate watermark configuration details now that derived - * plane/crtc state is all properly updated. - */ - drm_for_each_crtc(crtc, dev) { - cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?: - crtc->state; - - if (cstate->active) - intel_state->wm_config.num_pipes_active++; - } - drm_for_each_legacy_plane(plane, dev) { - pstate = drm_atomic_get_existing_plane_state(state, plane) ?: - plane->state; - - if (!to_intel_plane_state(pstate)->visible) - continue; - - intel_state->wm_config.sprites_enabled = true; - if (pstate->crtc_w != pstate->src_w >> 16 || - pstate->crtc_h != pstate->src_h >> 16) - intel_state->wm_config.sprites_scaled = true; - } -} - /** * intel_atomic_check - validate state object * @dev: drm device @@ -13094,7 +13049,6 @@ static void calc_watermark_data(struct drm_atomic_state *state) static int intel_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; @@ -13158,15 +13112,10 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; } else - intel_state->cdclk = to_i915(state->dev)->cdclk_freq; + to_intel_atomic_state(state)->cdclk = + to_i915(state->dev)->cdclk_freq; - ret = drm_atomic_helper_check_planes(state->dev, state); - if (ret) - return ret; - - calc_watermark_data(state); - - return 0; + return drm_atomic_helper_check_planes(state->dev, state); } /** @@ -13206,7 +13155,6 @@ static int intel_atomic_commit(struct drm_device *dev, return ret; drm_atomic_helper_swap_state(dev, state); - dev_priv->wm.config = to_intel_atomic_state(state)->wm_config; for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -15220,7 +15168,7 @@ static void readout_plane_state(struct intel_crtc *crtc) struct intel_plane_state *plane_state = to_intel_plane_state(primary->state); - plane_state->visible = crtc->active && + plane_state->visible = primary_get_hw_state(to_intel_plane(primary)); if (plane_state->visible) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e320825abd95..91b6b4060333 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -250,7 +250,6 @@ struct intel_atomic_state { unsigned int cdclk; bool dpll_set; struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; - struct intel_wm_config wm_config; }; struct intel_plane_state { @@ -335,21 +334,6 @@ struct intel_crtc_scaler_state { /* drm_mode->private_flags */ #define I915_MODE_FLAG_INHERITED 1 -struct intel_pipe_wm { - struct intel_wm_level wm[5]; - uint32_t linetime; - bool fbc_wm_enabled; - bool pipe_enabled; - bool sprites_enabled; - bool sprites_scaled; -}; - -struct skl_pipe_wm { - struct skl_wm_level wm[8]; - struct skl_wm_level trans_wm; - uint32_t linetime; -}; - struct intel_crtc_state { struct drm_crtc_state base; @@ -487,17 +471,6 @@ struct intel_crtc_state { /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */ bool disable_lp_wm; - - struct { - /* - * optimal watermarks, programmed post-vblank when this state - * is committed - */ - union { - struct intel_pipe_wm ilk; - struct skl_pipe_wm skl; - } optimal; - } wm; }; struct vlv_wm_state { @@ -509,6 +482,15 @@ struct vlv_wm_state { bool cxsr; }; +struct intel_pipe_wm { + struct intel_wm_level wm[5]; + uint32_t linetime; + bool fbc_wm_enabled; + bool pipe_enabled; + bool sprites_enabled; + bool sprites_scaled; +}; + struct intel_mmio_flip { struct work_struct work; struct drm_i915_private *i915; @@ -516,6 +498,12 @@ struct intel_mmio_flip { struct intel_crtc *crtc; }; +struct skl_pipe_wm { + struct skl_wm_level wm[8]; + struct skl_wm_level trans_wm; + uint32_t linetime; +}; + /* * Tracking of operations that need to be performed at the beginning/end of an * atomic commit, outside the atomic section where interrupts are disabled. @@ -583,10 +571,9 @@ struct intel_crtc { /* per-pipe watermark state */ struct { /* watermarks currently being used */ - union { - struct intel_pipe_wm ilk; - struct skl_pipe_wm skl; - } active; + struct intel_pipe_wm active; + /* SKL wm values currently in use */ + struct skl_pipe_wm skl_active; /* allow CxSR on this pipe */ bool cxsr_allowed; } wm; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3f9b3c078223..d031d74abd27 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1772,6 +1772,13 @@ struct ilk_wm_maximums { uint16_t fbc; }; +/* used in computing the new watermarks state */ +struct intel_wm_config { + unsigned int num_pipes_active; + bool sprites_enabled; + bool sprites_scaled; +}; + /* * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. @@ -2022,11 +2029,9 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, const struct intel_crtc *intel_crtc, int level, struct intel_crtc_state *cstate, - struct intel_plane_state *pristate, - struct intel_plane_state *sprstate, - struct intel_plane_state *curstate, struct intel_wm_level *result) { + struct intel_plane *intel_plane; uint16_t pri_latency = dev_priv->wm.pri_latency[level]; uint16_t spr_latency = dev_priv->wm.spr_latency[level]; uint16_t cur_latency = dev_priv->wm.cur_latency[level]; @@ -2038,11 +2043,29 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, cur_latency *= 5; } - result->pri_val = ilk_compute_pri_wm(cstate, pristate, - pri_latency, level); - result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency); - result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency); - result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val); + for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) { + struct intel_plane_state *pstate = + to_intel_plane_state(intel_plane->base.state); + + switch (intel_plane->base.type) { + case DRM_PLANE_TYPE_PRIMARY: + result->pri_val = ilk_compute_pri_wm(cstate, pstate, + pri_latency, + level); + result->fbc_val = ilk_compute_fbc_wm(cstate, pstate, + result->pri_val); + break; + case DRM_PLANE_TYPE_OVERLAY: + result->spr_val = ilk_compute_spr_wm(cstate, pstate, + spr_latency); + break; + case DRM_PLANE_TYPE_CURSOR: + result->cur_val = ilk_compute_cur_wm(cstate, pstate, + cur_latency); + break; + } + } + result->enable = true; } @@ -2301,19 +2324,34 @@ static void skl_setup_wm_latency(struct drm_device *dev) intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency); } -/* Compute new watermarks for the pipe */ -static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, - struct drm_atomic_state *state) +static void ilk_compute_wm_config(struct drm_device *dev, + struct intel_wm_config *config) { - struct intel_pipe_wm *pipe_wm; - struct drm_device *dev = intel_crtc->base.dev; + struct intel_crtc *intel_crtc; + + /* Compute the currently _active_ config */ + for_each_intel_crtc(dev, intel_crtc) { + const struct intel_pipe_wm *wm = &intel_crtc->wm.active; + + if (!wm->pipe_enabled) + continue; + + config->sprites_enabled |= wm->sprites_enabled; + config->sprites_scaled |= wm->sprites_scaled; + config->num_pipes_active++; + } +} + +/* Compute new watermarks for the pipe */ +static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, + struct intel_pipe_wm *pipe_wm) +{ + struct drm_crtc *crtc = cstate->base.crtc; + struct drm_device *dev = crtc->dev; const struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc_state *cstate = NULL; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane; - struct drm_plane_state *ps; - struct intel_plane_state *pristate = NULL; struct intel_plane_state *sprstate = NULL; - struct intel_plane_state *curstate = NULL; int level, max_level = ilk_wm_max_level(dev); /* LP0 watermark maximums depend on this pipe alone */ struct intel_wm_config config = { @@ -2321,24 +2359,11 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, }; struct ilk_wm_maximums max; - cstate = intel_atomic_get_crtc_state(state, intel_crtc); - if (IS_ERR(cstate)) - return PTR_ERR(cstate); - - pipe_wm = &cstate->wm.optimal.ilk; - for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - ps = drm_atomic_get_plane_state(state, - &intel_plane->base); - if (IS_ERR(ps)) - return PTR_ERR(ps); - - if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY) - pristate = to_intel_plane_state(ps); - else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) - sprstate = to_intel_plane_state(ps); - else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR) - curstate = to_intel_plane_state(ps); + if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) { + sprstate = to_intel_plane_state(intel_plane->base.state); + break; + } } config.sprites_enabled = sprstate->visible; @@ -2347,7 +2372,7 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16); pipe_wm->pipe_enabled = cstate->base.active; - pipe_wm->sprites_enabled = config.sprites_enabled; + pipe_wm->sprites_enabled = sprstate->visible; pipe_wm->sprites_scaled = config.sprites_scaled; /* ILK/SNB: LP2+ watermarks only w/o sprites */ @@ -2358,27 +2383,24 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, if (config.sprites_scaled) max_level = 0; - ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, - pristate, sprstate, curstate, &pipe_wm->wm[0]); + ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - pipe_wm->linetime = hsw_compute_linetime_wm(dev, - &intel_crtc->base); + pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); /* LP0 watermarks always use 1/2 DDB partitioning */ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); /* At least LP0 must be valid */ if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) - return -EINVAL; + return false; ilk_compute_wm_reg_maximums(dev, 1, &max); for (level = 1; level <= max_level; level++) { struct intel_wm_level wm = {}; - ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, - pristate, sprstate, curstate, &wm); + ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm); /* * Disable any watermark level that exceeds the @@ -2391,7 +2413,7 @@ static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, pipe_wm->wm[level] = wm; } - return 0; + return true; } /* @@ -2406,9 +2428,7 @@ static void ilk_merge_wm_level(struct drm_device *dev, ret_wm->enable = true; for_each_intel_crtc(dev, intel_crtc) { - const struct intel_crtc_state *cstate = - to_intel_crtc_state(intel_crtc->base.state); - const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk; + const struct intel_pipe_wm *active = &intel_crtc->wm.active; const struct intel_wm_level *wm = &active->wm[level]; if (!active->pipe_enabled) @@ -2556,15 +2576,14 @@ static void ilk_compute_wm_results(struct drm_device *dev, /* LP0 register values */ for_each_intel_crtc(dev, intel_crtc) { - const struct intel_crtc_state *cstate = - to_intel_crtc_state(intel_crtc->base.state); enum pipe pipe = intel_crtc->pipe; - const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0]; + const struct intel_wm_level *r = + &intel_crtc->wm.active.wm[0]; if (WARN_ON(!r->enable)) continue; - results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime; + results->wm_linetime[pipe] = intel_crtc->wm.active.linetime; results->wm_pipe[pipe] = (r->pri_val << WM0_PIPE_PLANE_SHIFT) | @@ -2946,12 +2965,11 @@ skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate) static void skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, + const struct intel_wm_config *config, struct skl_ddb_allocation *ddb /* out */) { struct drm_crtc *crtc = cstate->base.crtc; struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_wm_config *config = &dev_priv->wm.config; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane; enum pipe pipe = intel_crtc->pipe; @@ -3126,6 +3144,15 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb, return false; } +static void skl_compute_wm_global_parameters(struct drm_device *dev, + struct intel_wm_config *config) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + config->num_pipes_active += to_intel_crtc(crtc)->active; +} + static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, struct intel_crtc_state *cstate, struct intel_plane *intel_plane, @@ -3530,25 +3557,27 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, } static bool skl_update_pipe_wm(struct drm_crtc *crtc, + struct intel_wm_config *config, struct skl_ddb_allocation *ddb, /* out */ struct skl_pipe_wm *pipe_wm /* out */) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - skl_allocate_pipe_ddb(cstate, ddb); + skl_allocate_pipe_ddb(cstate, config, ddb); skl_compute_pipe_wm(cstate, ddb, pipe_wm); - if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm))) + if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) return false; - intel_crtc->wm.active.skl = *pipe_wm; + intel_crtc->wm.skl_active = *pipe_wm; return true; } static void skl_update_other_pipe_wm(struct drm_device *dev, struct drm_crtc *crtc, + struct intel_wm_config *config, struct skl_wm_values *r) { struct intel_crtc *intel_crtc; @@ -3578,7 +3607,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, if (!intel_crtc->active) continue; - wm_changed = skl_update_pipe_wm(&intel_crtc->base, + wm_changed = skl_update_pipe_wm(&intel_crtc->base, config, &r->ddb, &pipe_wm); /* @@ -3619,8 +3648,8 @@ static void skl_update_wm(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct skl_wm_values *results = &dev_priv->wm.skl_results; - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl; + struct skl_pipe_wm pipe_wm = {}; + struct intel_wm_config config = {}; /* Clear all dirty flags */ @@ -3628,13 +3657,15 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_clear_wm(results, intel_crtc->pipe); - if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm)) + skl_compute_wm_global_parameters(dev, &config); + + if (!skl_update_pipe_wm(crtc, &config, &results->ddb, &pipe_wm)) return; - skl_compute_wm_results(dev, pipe_wm, results, intel_crtc); + skl_compute_wm_results(dev, &pipe_wm, results, intel_crtc); results->dirty[intel_crtc->pipe] = true; - skl_update_other_pipe_wm(dev, crtc, results); + skl_update_other_pipe_wm(dev, crtc, &config, results); skl_write_wm_values(dev_priv, results); skl_flush_wm_values(dev_priv, results); @@ -3642,23 +3673,50 @@ static void skl_update_wm(struct drm_crtc *crtc) dev_priv->wm.skl_hw = *results; } -static void ilk_program_watermarks(struct drm_i915_private *dev_priv) +static void ilk_update_wm(struct drm_crtc *crtc) { - struct drm_device *dev = dev_priv->dev; - struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct ilk_wm_maximums max; - struct intel_wm_config *config = &dev_priv->wm.config; struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; + struct intel_pipe_wm pipe_wm = {}; + struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; + struct intel_wm_config config = {}; - ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max); - ilk_wm_merge(dev, config, &max, &lp_wm_1_2); + WARN_ON(cstate->base.active != intel_crtc->active); + + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + * + * WaCxSRDisabledForSpriteScaling:ivb + */ + if (cstate->disable_lp_wm) { + ilk_disable_lp_wm(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); + } + + intel_compute_pipe_wm(cstate, &pipe_wm); + + if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) + return; + + intel_crtc->wm.active = pipe_wm; + + ilk_compute_wm_config(dev, &config); + + ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); + ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_INFO(dev)->gen >= 7 && - config->num_pipes_active == 1 && config->sprites_enabled) { - ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max); - ilk_wm_merge(dev, config, &max, &lp_wm_5_6); + config.num_pipes_active == 1 && config.sprites_enabled) { + ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); + ilk_wm_merge(dev, &config, &max, &lp_wm_5_6); best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { @@ -3673,31 +3731,6 @@ static void ilk_program_watermarks(struct drm_i915_private *dev_priv) ilk_write_wm_values(dev_priv, &results); } -static void ilk_update_wm(struct drm_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - - WARN_ON(cstate->base.active != intel_crtc->active); - - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - * - * WaCxSRDisabledForSpriteScaling:ivb - */ - if (cstate->disable_lp_wm) { - ilk_disable_lp_wm(crtc->dev); - intel_wait_for_vblank(crtc->dev, intel_crtc->pipe); - } - - intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk; - - ilk_program_watermarks(dev_priv); -} - static void skl_pipe_wm_active_state(uint32_t val, struct skl_pipe_wm *active, bool is_transwm, @@ -3748,8 +3781,7 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct skl_wm_values *hw = &dev_priv->wm.skl_hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - struct skl_pipe_wm *active = &cstate->wm.optimal.skl; + struct skl_pipe_wm *active = &intel_crtc->wm.skl_active; enum pipe pipe = intel_crtc->pipe; int level, i, max_level; uint32_t temp; @@ -3793,8 +3825,6 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) temp = hw->plane_trans[pipe][PLANE_CURSOR]; skl_pipe_wm_active_state(temp, active, true, true, i, 0); - - intel_crtc->wm.active.skl = *active; } void skl_wm_get_hw_state(struct drm_device *dev) @@ -3814,8 +3844,7 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct ilk_wm_values *hw = &dev_priv->wm.hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - struct intel_pipe_wm *active = &cstate->wm.optimal.ilk; + struct intel_pipe_wm *active = &intel_crtc->wm.active; enum pipe pipe = intel_crtc->pipe; static const unsigned int wm0_pipe_reg[] = { [PIPE_A] = WM0_PIPEA_ILK, @@ -3854,8 +3883,6 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) for (level = 0; level <= max_level; level++) active->wm[level].enable = true; } - - intel_crtc->wm.active.ilk = *active; } #define _FW_WM(value, plane) \ @@ -7003,7 +7030,6 @@ void intel_init_pm(struct drm_device *dev) (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.update_wm = ilk_update_wm; - dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); From 80bea1897d7bc35e2b201847e12029a9d677cf12 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 10 Oct 2015 13:35:42 +0200 Subject: [PATCH 134/134] drm/i915: Update DRIVER_DATE to 20151010 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4feec193ff33..3c52a77220fa 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -57,7 +57,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150928" +#define DRIVER_DATE "20151010" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */