DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2006-2007 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Eric Anholt <eric@anholt.net>
|
|
|
|
|
*/
|
|
|
|
|
|
2012-04-01 13:38:50 +02:00
|
|
|
#include <linux/dmi.h>
|
2009-09-10 15:28:03 -07:00
|
|
|
#include <linux/module.h>
|
|
|
|
|
#include <linux/input.h>
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
#include <linux/i2c.h>
|
2009-06-26 11:23:55 +08:00
|
|
|
#include <linux/kernel.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 17:04:11 +09:00
|
|
|
#include <linux/slab.h>
|
2010-08-13 15:11:26 -07:00
|
|
|
#include <linux/vgaarb.h>
|
drm/i915: pass ELD to HDMI/DP audio driver
Add ELD support for Intel Eaglelake, IbexPeak/Ironlake,
SandyBridge/CougarPoint and IvyBridge/PantherPoint chips.
ELD (EDID-Like Data) describes to the HDMI/DP audio driver the audio
capabilities of the plugged monitor. It's built and passed to audio
driver in 2 steps:
(1) at get_modes time, parse EDID and save ELD to drm_connector.eld[]
(2) at mode_set time, write drm_connector.eld[] to the Transcoder's hw
ELD buffer and set the ELD_valid bit to inform HDMI/DP audio driver
This patch is tested OK on G45/HDMI, IbexPeak/HDMI and IvyBridge/HDMI+DP.
Test scheme: plug in the HDMI/DP monitor, and run
cat /proc/asound/card0/eld*
to check if the monitor name, HDMI/DP type, etc. show up correctly.
Minor imperfection: the GEN5_AUD_CNTL_ST/DIP_Port_Select field always
reads 0 (reserved). Without knowing the port number, I worked it around
by setting the ELD_valid bit for ALL the three ports. It's tested to not
be a problem, because the audio driver will find invalid ELD data and
hence rightfully abort, even when it sees the ELD_valid indicator.
Thanks to Zhenyu and Pierre-Louis for a lot of valuable help and testing.
CC: Zhao Yakui <yakui.zhao@intel.com>
CC: Wang Zhenyu <zhenyu.z.wang@intel.com>
CC: Jeremy Bush <contractfrombelow@gmail.com>
CC: Christopher White <c.white@pulseforce.com>
CC: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
CC: Paul Menzel <paulepanter@users.sourceforge.net>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
2011-09-05 14:25:34 +08:00
|
|
|
#include <drm/drm_edid.h>
|
2012-10-02 18:01:07 +01:00
|
|
|
#include <drm/drmP.h>
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
#include "intel_drv.h"
|
2016-08-04 16:32:35 +01:00
|
|
|
#include "intel_frontbuffer.h"
|
2012-10-02 18:01:07 +01:00
|
|
|
#include <drm/i915_drm.h>
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
#include "i915_drv.h"
|
2017-02-22 11:40:48 +00:00
|
|
|
#include "i915_gem_clflush.h"
|
2016-03-24 12:41:40 +02:00
|
|
|
#include "intel_dsi.h"
|
2010-07-01 16:48:37 -07:00
|
|
|
#include "i915_trace.h"
|
2015-03-12 20:16:32 +08:00
|
|
|
#include <drm/drm_atomic.h>
|
2015-01-21 16:35:48 -08:00
|
|
|
#include <drm/drm_atomic_helper.h>
|
2012-10-02 18:01:07 +01:00
|
|
|
#include <drm/drm_dp_helper.h>
|
|
|
|
|
#include <drm/drm_crtc_helper.h>
|
2014-05-29 08:06:54 -07:00
|
|
|
#include <drm/drm_plane_helper.h>
|
|
|
|
|
#include <drm/drm_rect.h>
|
2011-11-16 22:24:52 -08:00
|
|
|
#include <linux/dma_remapping.h>
|
2015-11-25 18:43:38 -08:00
|
|
|
#include <linux/reservation.h>
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2014-05-29 08:06:54 -07:00
|
|
|
/* Primary plane formats for gen <= 3 */
|
2015-05-12 16:13:18 +01:00
|
|
|
static const uint32_t i8xx_primary_formats[] = {
|
2015-05-15 19:06:00 +01:00
|
|
|
DRM_FORMAT_C8,
|
|
|
|
|
DRM_FORMAT_RGB565,
|
2014-05-29 08:06:54 -07:00
|
|
|
DRM_FORMAT_XRGB1555,
|
2015-05-15 19:06:00 +01:00
|
|
|
DRM_FORMAT_XRGB8888,
|
2014-05-29 08:06:54 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Primary plane formats for gen >= 4 */
|
2015-05-12 16:13:18 +01:00
|
|
|
static const uint32_t i965_primary_formats[] = {
|
2015-05-19 12:29:16 +01:00
|
|
|
DRM_FORMAT_C8,
|
|
|
|
|
DRM_FORMAT_RGB565,
|
|
|
|
|
DRM_FORMAT_XRGB8888,
|
|
|
|
|
DRM_FORMAT_XBGR8888,
|
|
|
|
|
DRM_FORMAT_XRGB2101010,
|
|
|
|
|
DRM_FORMAT_XBGR2101010,
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-01 09:58:16 -07:00
|
|
|
static const uint64_t i9xx_format_modifiers[] = {
|
|
|
|
|
I915_FORMAT_MOD_X_TILED,
|
|
|
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
|
|
|
DRM_FORMAT_MOD_INVALID
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-19 12:29:16 +01:00
|
|
|
static const uint32_t skl_primary_formats[] = {
|
2015-05-15 19:06:00 +01:00
|
|
|
DRM_FORMAT_C8,
|
|
|
|
|
DRM_FORMAT_RGB565,
|
|
|
|
|
DRM_FORMAT_XRGB8888,
|
2014-05-29 08:06:54 -07:00
|
|
|
DRM_FORMAT_XBGR8888,
|
2015-05-15 19:06:00 +01:00
|
|
|
DRM_FORMAT_ARGB8888,
|
2014-05-29 08:06:54 -07:00
|
|
|
DRM_FORMAT_ABGR8888,
|
|
|
|
|
DRM_FORMAT_XRGB2101010,
|
|
|
|
|
DRM_FORMAT_XBGR2101010,
|
2015-09-03 16:17:09 +05:30
|
|
|
DRM_FORMAT_YUYV,
|
|
|
|
|
DRM_FORMAT_YVYU,
|
|
|
|
|
DRM_FORMAT_UYVY,
|
|
|
|
|
DRM_FORMAT_VYUY,
|
2014-05-29 08:06:54 -07:00
|
|
|
};
|
|
|
|
|
|
2017-08-01 09:58:16 -07:00
|
|
|
static const uint64_t skl_format_modifiers_noccs[] = {
|
|
|
|
|
I915_FORMAT_MOD_Yf_TILED,
|
|
|
|
|
I915_FORMAT_MOD_Y_TILED,
|
|
|
|
|
I915_FORMAT_MOD_X_TILED,
|
|
|
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
|
|
|
DRM_FORMAT_MOD_INVALID
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const uint64_t skl_format_modifiers_ccs[] = {
|
|
|
|
|
I915_FORMAT_MOD_Yf_TILED_CCS,
|
|
|
|
|
I915_FORMAT_MOD_Y_TILED_CCS,
|
|
|
|
|
I915_FORMAT_MOD_Yf_TILED,
|
|
|
|
|
I915_FORMAT_MOD_Y_TILED,
|
|
|
|
|
I915_FORMAT_MOD_X_TILED,
|
|
|
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
|
|
|
DRM_FORMAT_MOD_INVALID
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-10 08:28:13 -07:00
|
|
|
/* Cursor formats */
|
|
|
|
|
static const uint32_t intel_cursor_formats[] = {
|
|
|
|
|
DRM_FORMAT_ARGB8888,
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-01 09:58:16 -07:00
|
|
|
static const uint64_t cursor_format_modifiers[] = {
|
|
|
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
|
|
|
DRM_FORMAT_MOD_INVALID
|
|
|
|
|
};
|
|
|
|
|
|
2013-06-27 00:39:25 +03:00
|
|
|
static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config);
|
2013-09-13 16:00:08 +03:00
|
|
|
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config);
|
2013-06-27 00:39:25 +03:00
|
|
|
|
2017-02-15 10:59:18 +00:00
|
|
|
static int intel_framebuffer_init(struct intel_framebuffer *ifb,
|
|
|
|
|
struct drm_i915_gem_object *obj,
|
|
|
|
|
struct drm_mode_fb_cmd2 *mode_cmd);
|
2014-04-24 23:55:06 +02:00
|
|
|
static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc);
|
|
|
|
|
static void intel_set_pipe_timings(struct intel_crtc *intel_crtc);
|
2016-03-18 17:05:39 +02:00
|
|
|
static void intel_set_pipe_src_size(struct intel_crtc *intel_crtc);
|
2014-04-24 23:55:08 +02:00
|
|
|
static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
|
2014-08-05 07:51:22 -07:00
|
|
|
struct intel_link_m_n *m_n,
|
|
|
|
|
struct intel_link_m_n *m2_n2);
|
2014-04-24 23:55:08 +02:00
|
|
|
static void ironlake_set_pipeconf(struct drm_crtc *crtc);
|
2014-04-24 23:55:09 +02:00
|
|
|
static void haswell_set_pipeconf(struct drm_crtc *crtc);
|
2016-03-18 17:05:40 +02:00
|
|
|
static void haswell_set_pipemisc(struct drm_crtc *crtc);
|
2014-10-28 13:20:22 +02:00
|
|
|
static void vlv_prepare_pll(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
const struct intel_crtc_state *pipe_config);
|
2014-10-28 13:20:22 +02:00
|
|
|
static void chv_prepare_pll(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
const struct intel_crtc_state *pipe_config);
|
2016-05-24 17:13:53 +02:00
|
|
|
static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
|
|
|
|
|
static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *);
|
2016-11-29 11:23:14 +05:30
|
|
|
static void intel_crtc_init_scalers(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state);
|
2015-08-27 15:44:05 +02:00
|
|
|
static void skylake_pfit_enable(struct intel_crtc *crtc);
|
|
|
|
|
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
|
|
|
|
|
static void ironlake_pfit_enable(struct intel_crtc *crtc);
|
2017-06-01 17:36:13 +03:00
|
|
|
static void intel_modeset_setup_hw_state(struct drm_device *dev,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx);
|
2016-03-09 19:07:26 +02:00
|
|
|
static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
|
2013-08-08 22:28:59 +01:00
|
|
|
|
2009-03-18 20:13:27 +08:00
|
|
|
struct intel_limit {
|
2016-05-04 12:11:58 +03:00
|
|
|
struct {
|
|
|
|
|
int min, max;
|
|
|
|
|
} dot, vco, n, m, m1, m2, p, p1;
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
int dot_limit;
|
|
|
|
|
int p2_slow, p2_fast;
|
|
|
|
|
} p2;
|
2009-03-18 20:13:27 +08:00
|
|
|
};
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2015-09-24 23:29:18 +03:00
|
|
|
/* returns HPLL frequency in kHz */
|
2017-02-07 20:33:45 +02:00
|
|
|
int vlv_get_hpll_vco(struct drm_i915_private *dev_priv)
|
2015-09-24 23:29:18 +03:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-04 21:43:02 +02:00
|
|
|
int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
|
|
|
|
|
const char *name, u32 reg, int ref_freq)
|
2015-09-24 23:29:18 +03:00
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
int divider;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2016-03-04 21:43:02 +02:00
|
|
|
return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
|
|
|
|
|
const char *name, u32 reg)
|
2016-03-04 21:43:02 +02:00
|
|
|
{
|
|
|
|
|
if (dev_priv->hpll_freq == 0)
|
2017-02-07 20:33:45 +02:00
|
|
|
dev_priv->hpll_freq = vlv_get_hpll_vco(dev_priv);
|
2016-03-04 21:43:02 +02:00
|
|
|
|
|
|
|
|
return vlv_get_cck_clock(dev_priv, name, reg,
|
|
|
|
|
dev_priv->hpll_freq);
|
2015-09-24 23:29:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_update_czclk(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
2015-12-09 12:29:35 -08:00
|
|
|
if (!(IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)))
|
2015-09-24 23:29:18 +03:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-07 20:54:59 +01:00
|
|
|
static inline u32 /* units of 100MHz */
|
2016-02-17 21:41:10 +02:00
|
|
|
intel_fdi_link_freq(struct drm_i915_private *dev_priv,
|
|
|
|
|
const struct intel_crtc_state *pipe_config)
|
2010-09-07 20:54:59 +01:00
|
|
|
{
|
2016-02-17 21:41:10 +02:00
|
|
|
if (HAS_DDI(dev_priv))
|
|
|
|
|
return pipe_config->port_clock; /* SPLL */
|
2016-02-17 21:41:09 +02:00
|
|
|
else
|
2017-11-05 13:49:05 +00:00
|
|
|
return dev_priv->fdi_pll_freq;
|
2010-09-07 20:54:59 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_i8xx_dac = {
|
2011-08-16 15:34:10 -04:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
2013-12-09 18:54:17 +02:00
|
|
|
.vco = { .min = 908000, .max = 1512000 },
|
2013-12-09 18:54:14 +02:00
|
|
|
.n = { .min = 2, .max = 16 },
|
2011-08-16 15:34:10 -04:00
|
|
|
.m = { .min = 96, .max = 140 },
|
|
|
|
|
.m1 = { .min = 18, .max = 26 },
|
|
|
|
|
.m2 = { .min = 6, .max = 16 },
|
|
|
|
|
.p = { .min = 4, .max = 128 },
|
|
|
|
|
.p1 = { .min = 2, .max = 33 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 165000,
|
|
|
|
|
.p2_slow = 4, .p2_fast = 2 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_i8xx_dvo = {
|
2013-07-06 12:52:06 +02:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
2013-12-09 18:54:17 +02:00
|
|
|
.vco = { .min = 908000, .max = 1512000 },
|
2013-12-09 18:54:14 +02:00
|
|
|
.n = { .min = 2, .max = 16 },
|
2013-07-06 12:52:06 +02:00
|
|
|
.m = { .min = 96, .max = 140 },
|
|
|
|
|
.m1 = { .min = 18, .max = 26 },
|
|
|
|
|
.m2 = { .min = 6, .max = 16 },
|
|
|
|
|
.p = { .min = 4, .max = 128 },
|
|
|
|
|
.p1 = { .min = 2, .max = 33 },
|
|
|
|
|
.p2 = { .dot_limit = 165000,
|
|
|
|
|
.p2_slow = 4, .p2_fast = 4 },
|
|
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_i8xx_lvds = {
|
2011-08-16 15:34:10 -04:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
2013-12-09 18:54:17 +02:00
|
|
|
.vco = { .min = 908000, .max = 1512000 },
|
2013-12-09 18:54:14 +02:00
|
|
|
.n = { .min = 2, .max = 16 },
|
2011-08-16 15:34:10 -04:00
|
|
|
.m = { .min = 96, .max = 140 },
|
|
|
|
|
.m1 = { .min = 18, .max = 26 },
|
|
|
|
|
.m2 = { .min = 6, .max = 16 },
|
|
|
|
|
.p = { .min = 4, .max = 128 },
|
|
|
|
|
.p1 = { .min = 1, .max = 6 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 165000,
|
|
|
|
|
.p2_slow = 14, .p2_fast = 7 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
2011-03-30 13:01:10 -07:00
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_i9xx_sdvo = {
|
2011-08-16 15:34:10 -04:00
|
|
|
.dot = { .min = 20000, .max = 400000 },
|
|
|
|
|
.vco = { .min = 1400000, .max = 2800000 },
|
|
|
|
|
.n = { .min = 1, .max = 6 },
|
|
|
|
|
.m = { .min = 70, .max = 120 },
|
2013-02-13 22:20:22 +01:00
|
|
|
.m1 = { .min = 8, .max = 18 },
|
|
|
|
|
.m2 = { .min = 3, .max = 7 },
|
2011-08-16 15:34:10 -04:00
|
|
|
.p = { .min = 5, .max = 80 },
|
|
|
|
|
.p1 = { .min = 1, .max = 8 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 200000,
|
|
|
|
|
.p2_slow = 10, .p2_fast = 5 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_i9xx_lvds = {
|
2011-08-16 15:34:10 -04:00
|
|
|
.dot = { .min = 20000, .max = 400000 },
|
|
|
|
|
.vco = { .min = 1400000, .max = 2800000 },
|
|
|
|
|
.n = { .min = 1, .max = 6 },
|
|
|
|
|
.m = { .min = 70, .max = 120 },
|
2013-02-13 22:20:21 +01:00
|
|
|
.m1 = { .min = 8, .max = 18 },
|
|
|
|
|
.m2 = { .min = 3, .max = 7 },
|
2011-08-16 15:34:10 -04:00
|
|
|
.p = { .min = 7, .max = 98 },
|
|
|
|
|
.p1 = { .min = 1, .max = 8 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 112000,
|
|
|
|
|
.p2_slow = 14, .p2_fast = 7 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2011-03-30 13:01:10 -07:00
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_g4x_sdvo = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 25000, .max = 270000 },
|
|
|
|
|
.vco = { .min = 1750000, .max = 3500000},
|
|
|
|
|
.n = { .min = 1, .max = 4 },
|
|
|
|
|
.m = { .min = 104, .max = 138 },
|
|
|
|
|
.m1 = { .min = 17, .max = 23 },
|
|
|
|
|
.m2 = { .min = 5, .max = 11 },
|
|
|
|
|
.p = { .min = 10, .max = 30 },
|
|
|
|
|
.p1 = { .min = 1, .max = 3},
|
|
|
|
|
.p2 = { .dot_limit = 270000,
|
|
|
|
|
.p2_slow = 10,
|
|
|
|
|
.p2_fast = 10
|
2009-03-18 20:13:23 +08:00
|
|
|
},
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_g4x_hdmi = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 22000, .max = 400000 },
|
|
|
|
|
.vco = { .min = 1750000, .max = 3500000},
|
|
|
|
|
.n = { .min = 1, .max = 4 },
|
|
|
|
|
.m = { .min = 104, .max = 138 },
|
|
|
|
|
.m1 = { .min = 16, .max = 23 },
|
|
|
|
|
.m2 = { .min = 5, .max = 11 },
|
|
|
|
|
.p = { .min = 5, .max = 80 },
|
|
|
|
|
.p1 = { .min = 1, .max = 8},
|
|
|
|
|
.p2 = { .dot_limit = 165000,
|
|
|
|
|
.p2_slow = 10, .p2_fast = 5 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_g4x_single_channel_lvds = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 20000, .max = 115000 },
|
|
|
|
|
.vco = { .min = 1750000, .max = 3500000 },
|
|
|
|
|
.n = { .min = 1, .max = 3 },
|
|
|
|
|
.m = { .min = 104, .max = 138 },
|
|
|
|
|
.m1 = { .min = 17, .max = 23 },
|
|
|
|
|
.m2 = { .min = 5, .max = 11 },
|
|
|
|
|
.p = { .min = 28, .max = 112 },
|
|
|
|
|
.p1 = { .min = 2, .max = 8 },
|
|
|
|
|
.p2 = { .dot_limit = 0,
|
|
|
|
|
.p2_slow = 14, .p2_fast = 14
|
2009-03-18 20:13:23 +08:00
|
|
|
},
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_g4x_dual_channel_lvds = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 80000, .max = 224000 },
|
|
|
|
|
.vco = { .min = 1750000, .max = 3500000 },
|
|
|
|
|
.n = { .min = 1, .max = 3 },
|
|
|
|
|
.m = { .min = 104, .max = 138 },
|
|
|
|
|
.m1 = { .min = 17, .max = 23 },
|
|
|
|
|
.m2 = { .min = 5, .max = 11 },
|
|
|
|
|
.p = { .min = 14, .max = 42 },
|
|
|
|
|
.p1 = { .min = 2, .max = 6 },
|
|
|
|
|
.p2 = { .dot_limit = 0,
|
|
|
|
|
.p2_slow = 7, .p2_fast = 7
|
2009-03-18 20:13:23 +08:00
|
|
|
},
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_pineview_sdvo = {
|
2011-08-16 15:34:10 -04:00
|
|
|
.dot = { .min = 20000, .max = 400000},
|
|
|
|
|
.vco = { .min = 1700000, .max = 3500000 },
|
2011-03-30 13:01:10 -07:00
|
|
|
/* Pineview's Ncounter is a ring counter */
|
2011-08-16 15:34:10 -04:00
|
|
|
.n = { .min = 3, .max = 6 },
|
|
|
|
|
.m = { .min = 2, .max = 256 },
|
2011-03-30 13:01:10 -07:00
|
|
|
/* Pineview only has one combined m divider, which we treat as m2. */
|
2011-08-16 15:34:10 -04:00
|
|
|
.m1 = { .min = 0, .max = 0 },
|
|
|
|
|
.m2 = { .min = 0, .max = 254 },
|
|
|
|
|
.p = { .min = 5, .max = 80 },
|
|
|
|
|
.p1 = { .min = 1, .max = 8 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 200000,
|
|
|
|
|
.p2_slow = 10, .p2_fast = 5 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_pineview_lvds = {
|
2011-08-16 15:34:10 -04:00
|
|
|
.dot = { .min = 20000, .max = 400000 },
|
|
|
|
|
.vco = { .min = 1700000, .max = 3500000 },
|
|
|
|
|
.n = { .min = 3, .max = 6 },
|
|
|
|
|
.m = { .min = 2, .max = 256 },
|
|
|
|
|
.m1 = { .min = 0, .max = 0 },
|
|
|
|
|
.m2 = { .min = 0, .max = 254 },
|
|
|
|
|
.p = { .min = 7, .max = 112 },
|
|
|
|
|
.p1 = { .min = 1, .max = 8 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 112000,
|
|
|
|
|
.p2_slow = 14, .p2_fast = 14 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2011-03-30 13:01:10 -07:00
|
|
|
/* Ironlake / Sandybridge
|
|
|
|
|
*
|
|
|
|
|
* We calculate clock using (register_value + 2) for N/M1/M2, so here
|
|
|
|
|
* the range value for them is (actual_value - 2).
|
|
|
|
|
*/
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_ironlake_dac = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
|
|
|
|
.vco = { .min = 1760000, .max = 3510000 },
|
|
|
|
|
.n = { .min = 1, .max = 5 },
|
|
|
|
|
.m = { .min = 79, .max = 127 },
|
|
|
|
|
.m1 = { .min = 12, .max = 22 },
|
|
|
|
|
.m2 = { .min = 5, .max = 9 },
|
|
|
|
|
.p = { .min = 5, .max = 80 },
|
|
|
|
|
.p1 = { .min = 1, .max = 8 },
|
|
|
|
|
.p2 = { .dot_limit = 225000,
|
|
|
|
|
.p2_slow = 10, .p2_fast = 5 },
|
2009-06-05 19:22:17 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_ironlake_single_lvds = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
|
|
|
|
.vco = { .min = 1760000, .max = 3510000 },
|
|
|
|
|
.n = { .min = 1, .max = 3 },
|
|
|
|
|
.m = { .min = 79, .max = 118 },
|
|
|
|
|
.m1 = { .min = 12, .max = 22 },
|
|
|
|
|
.m2 = { .min = 5, .max = 9 },
|
|
|
|
|
.p = { .min = 28, .max = 112 },
|
|
|
|
|
.p1 = { .min = 2, .max = 8 },
|
|
|
|
|
.p2 = { .dot_limit = 225000,
|
|
|
|
|
.p2_slow = 14, .p2_fast = 14 },
|
2010-02-05 09:14:17 +08:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_ironlake_dual_lvds = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
|
|
|
|
.vco = { .min = 1760000, .max = 3510000 },
|
|
|
|
|
.n = { .min = 1, .max = 3 },
|
|
|
|
|
.m = { .min = 79, .max = 127 },
|
|
|
|
|
.m1 = { .min = 12, .max = 22 },
|
|
|
|
|
.m2 = { .min = 5, .max = 9 },
|
|
|
|
|
.p = { .min = 14, .max = 56 },
|
|
|
|
|
.p1 = { .min = 2, .max = 8 },
|
|
|
|
|
.p2 = { .dot_limit = 225000,
|
|
|
|
|
.p2_slow = 7, .p2_fast = 7 },
|
2010-02-05 09:14:17 +08:00
|
|
|
};
|
|
|
|
|
|
2011-03-30 13:01:10 -07:00
|
|
|
/* LVDS 100mhz refclk limits. */
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_ironlake_single_lvds_100m = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
|
|
|
|
.vco = { .min = 1760000, .max = 3510000 },
|
|
|
|
|
.n = { .min = 1, .max = 2 },
|
|
|
|
|
.m = { .min = 79, .max = 126 },
|
|
|
|
|
.m1 = { .min = 12, .max = 22 },
|
|
|
|
|
.m2 = { .min = 5, .max = 9 },
|
|
|
|
|
.p = { .min = 28, .max = 112 },
|
2011-08-16 15:34:10 -04:00
|
|
|
.p1 = { .min = 2, .max = 8 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 225000,
|
|
|
|
|
.p2_slow = 14, .p2_fast = 14 },
|
2010-02-05 09:14:17 +08:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_ironlake_dual_lvds_100m = {
|
2011-03-30 13:01:10 -07:00
|
|
|
.dot = { .min = 25000, .max = 350000 },
|
|
|
|
|
.vco = { .min = 1760000, .max = 3510000 },
|
|
|
|
|
.n = { .min = 1, .max = 3 },
|
|
|
|
|
.m = { .min = 79, .max = 126 },
|
|
|
|
|
.m1 = { .min = 12, .max = 22 },
|
|
|
|
|
.m2 = { .min = 5, .max = 9 },
|
|
|
|
|
.p = { .min = 14, .max = 42 },
|
2011-08-16 15:34:10 -04:00
|
|
|
.p1 = { .min = 2, .max = 6 },
|
2011-03-30 13:01:10 -07:00
|
|
|
.p2 = { .dot_limit = 225000,
|
|
|
|
|
.p2_slow = 7, .p2_fast = 7 },
|
2009-12-31 16:06:04 +08:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_vlv = {
|
2013-09-27 16:55:49 +03:00
|
|
|
/*
|
|
|
|
|
* These are the data rate limits (measured in fast clocks)
|
|
|
|
|
* since those are the strictest limits we have. The fast
|
|
|
|
|
* clock and actual rate limits are more relaxed, so checking
|
|
|
|
|
* them would make no difference.
|
|
|
|
|
*/
|
|
|
|
|
.dot = { .min = 25000 * 5, .max = 270000 * 5 },
|
2013-04-18 21:10:43 +02:00
|
|
|
.vco = { .min = 4000000, .max = 6000000 },
|
2012-06-15 11:55:13 -07:00
|
|
|
.n = { .min = 1, .max = 7 },
|
|
|
|
|
.m1 = { .min = 2, .max = 3 },
|
|
|
|
|
.m2 = { .min = 11, .max = 156 },
|
2013-09-24 21:26:26 +03:00
|
|
|
.p1 = { .min = 2, .max = 3 },
|
2013-09-24 21:26:29 +03:00
|
|
|
.p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */
|
2012-06-15 11:55:13 -07:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_chv = {
|
2014-04-09 13:28:18 +03:00
|
|
|
/*
|
|
|
|
|
* These are the data rate limits (measured in fast clocks)
|
|
|
|
|
* since those are the strictest limits we have. The fast
|
|
|
|
|
* clock and actual rate limits are more relaxed, so checking
|
|
|
|
|
* them would make no difference.
|
|
|
|
|
*/
|
|
|
|
|
.dot = { .min = 25000 * 5, .max = 540000 * 5},
|
2015-02-26 21:01:52 +02:00
|
|
|
.vco = { .min = 4800000, .max = 6480000 },
|
2014-04-09 13:28:18 +03:00
|
|
|
.n = { .min = 1, .max = 1 },
|
|
|
|
|
.m1 = { .min = 2, .max = 2 },
|
|
|
|
|
.m2 = { .min = 24 << 22, .max = 175 << 22 },
|
|
|
|
|
.p1 = { .min = 2, .max = 4 },
|
|
|
|
|
.p2 = { .p2_slow = 1, .p2_fast = 14 },
|
|
|
|
|
};
|
|
|
|
|
|
2016-05-04 12:11:59 +03:00
|
|
|
static const struct intel_limit intel_limits_bxt = {
|
2015-03-06 03:29:25 +02:00
|
|
|
/* FIXME: find real dot limits */
|
|
|
|
|
.dot = { .min = 0, .max = INT_MAX },
|
2015-07-01 17:02:57 +05:30
|
|
|
.vco = { .min = 4800000, .max = 6700000 },
|
2015-03-06 03:29:25 +02:00
|
|
|
.n = { .min = 1, .max = 1 },
|
|
|
|
|
.m1 = { .min = 2, .max = 2 },
|
|
|
|
|
/* FIXME: find real m2 limits */
|
|
|
|
|
.m2 = { .min = 2 << 22, .max = 255 << 22 },
|
|
|
|
|
.p1 = { .min = 2, .max = 4 },
|
|
|
|
|
.p2 = { .p2_slow = 1, .p2_fast = 20 },
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-01 12:49:51 +02:00
|
|
|
static bool
|
2017-11-22 19:39:01 +01:00
|
|
|
needs_modeset(const struct drm_crtc_state *state)
|
2015-06-01 12:49:51 +02:00
|
|
|
{
|
2015-07-21 13:28:57 +02:00
|
|
|
return drm_atomic_crtc_needs_modeset(state);
|
2015-06-01 12:49:51 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
/*
|
|
|
|
|
* Platform specific helpers to calculate the port PLL loopback- (clock.m),
|
|
|
|
|
* and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
|
|
|
|
|
* (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic.
|
|
|
|
|
* The helpers' return value is the rate of the clock that is fed to the
|
|
|
|
|
* display engine's pipe which can be the above fast dot clock rate or a
|
|
|
|
|
* divided-down version of it.
|
|
|
|
|
*/
|
2009-12-03 17:14:42 -05:00
|
|
|
/* m1 is reserved as 0 in Pineview, n is a ring counter */
|
2016-05-04 12:11:57 +03:00
|
|
|
static int pnv_calc_dpll_params(int refclk, struct dpll *clock)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2009-02-23 15:19:16 +08:00
|
|
|
clock->m = clock->m2 + 2;
|
|
|
|
|
clock->p = clock->p1 * clock->p2;
|
2013-12-02 19:00:45 +02:00
|
|
|
if (WARN_ON(clock->n == 0 || clock->p == 0))
|
2015-06-22 23:35:51 +03:00
|
|
|
return 0;
|
2013-10-14 14:50:30 +03:00
|
|
|
clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
|
|
|
|
|
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
|
2015-06-22 23:35:51 +03:00
|
|
|
|
|
|
|
|
return clock->dot;
|
2009-02-23 15:19:16 +08:00
|
|
|
}
|
|
|
|
|
|
2013-04-20 17:19:46 +02:00
|
|
|
static uint32_t i9xx_dpll_compute_m(struct dpll *dpll)
|
|
|
|
|
{
|
|
|
|
|
return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-04 12:11:57 +03:00
|
|
|
static int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
|
2009-02-23 15:19:16 +08:00
|
|
|
{
|
2013-04-20 17:19:46 +02:00
|
|
|
clock->m = i9xx_dpll_compute_m(clock);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
clock->p = clock->p1 * clock->p2;
|
2013-12-02 19:00:45 +02:00
|
|
|
if (WARN_ON(clock->n + 2 == 0 || clock->p == 0))
|
2015-06-22 23:35:51 +03:00
|
|
|
return 0;
|
2013-10-14 14:50:30 +03:00
|
|
|
clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2);
|
|
|
|
|
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
|
2015-06-22 23:35:51 +03:00
|
|
|
|
|
|
|
|
return clock->dot;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2016-05-04 12:11:57 +03:00
|
|
|
static int vlv_calc_dpll_params(int refclk, struct dpll *clock)
|
2015-06-22 23:35:50 +03:00
|
|
|
{
|
|
|
|
|
clock->m = clock->m1 * clock->m2;
|
|
|
|
|
clock->p = clock->p1 * clock->p2;
|
|
|
|
|
if (WARN_ON(clock->n == 0 || clock->p == 0))
|
2015-06-22 23:35:51 +03:00
|
|
|
return 0;
|
2015-06-22 23:35:50 +03:00
|
|
|
clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
|
|
|
|
|
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
|
2015-06-22 23:35:51 +03:00
|
|
|
|
|
|
|
|
return clock->dot / 5;
|
2015-06-22 23:35:50 +03:00
|
|
|
}
|
|
|
|
|
|
2016-05-04 12:11:57 +03:00
|
|
|
int chv_calc_dpll_params(int refclk, struct dpll *clock)
|
2014-04-09 13:28:18 +03:00
|
|
|
{
|
|
|
|
|
clock->m = clock->m1 * clock->m2;
|
|
|
|
|
clock->p = clock->p1 * clock->p2;
|
|
|
|
|
if (WARN_ON(clock->n == 0 || clock->p == 0))
|
2015-06-22 23:35:51 +03:00
|
|
|
return 0;
|
2014-04-09 13:28:18 +03:00
|
|
|
clock->vco = DIV_ROUND_CLOSEST_ULL((uint64_t)refclk * clock->m,
|
|
|
|
|
clock->n << 22);
|
|
|
|
|
clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
|
2015-06-22 23:35:51 +03:00
|
|
|
|
|
|
|
|
return clock->dot / 5;
|
2014-04-09 13:28:18 +03:00
|
|
|
}
|
|
|
|
|
|
2009-02-23 15:36:40 -08:00
|
|
|
#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/**
|
|
|
|
|
* Returns whether the given set of divisors are valid for a given refclk with
|
|
|
|
|
* the given connectors.
|
|
|
|
|
*/
|
|
|
|
|
|
2016-10-13 11:03:04 +01:00
|
|
|
static bool intel_PLL_is_valid(struct drm_i915_private *dev_priv,
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit,
|
2016-05-04 12:11:57 +03:00
|
|
|
const struct dpll *clock)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2013-09-27 16:55:49 +03:00
|
|
|
if (clock->n < limit->n.min || limit->n.max < clock->n)
|
|
|
|
|
INTELPllInvalid("n out of range\n");
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
|
2011-08-16 15:34:10 -04:00
|
|
|
INTELPllInvalid("p1 out of range\n");
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
|
2011-08-16 15:34:10 -04:00
|
|
|
INTELPllInvalid("m2 out of range\n");
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
|
2011-08-16 15:34:10 -04:00
|
|
|
INTELPllInvalid("m1 out of range\n");
|
2013-09-27 16:55:49 +03:00
|
|
|
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!IS_PINEVIEW(dev_priv) && !IS_VALLEYVIEW(dev_priv) &&
|
2016-12-02 10:23:49 +02:00
|
|
|
!IS_CHERRYVIEW(dev_priv) && !IS_GEN9_LP(dev_priv))
|
2013-09-27 16:55:49 +03:00
|
|
|
if (clock->m1 <= clock->m2)
|
|
|
|
|
INTELPllInvalid("m1 <= m2\n");
|
|
|
|
|
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
|
2016-12-02 10:23:49 +02:00
|
|
|
!IS_GEN9_LP(dev_priv)) {
|
2013-09-27 16:55:49 +03:00
|
|
|
if (clock->p < limit->p.min || limit->p.max < clock->p)
|
|
|
|
|
INTELPllInvalid("p out of range\n");
|
|
|
|
|
if (clock->m < limit->m.min || limit->m.max < clock->m)
|
|
|
|
|
INTELPllInvalid("m out of range\n");
|
|
|
|
|
}
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
|
2011-08-16 15:34:10 -04:00
|
|
|
INTELPllInvalid("vco out of range\n");
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/* XXX: We may need to be checking "Dot clock" depending on the multiplier,
|
|
|
|
|
* connector, etc., rather than just a single range.
|
|
|
|
|
*/
|
|
|
|
|
if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
|
2011-08-16 15:34:10 -04:00
|
|
|
INTELPllInvalid("dot out of range\n");
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-18 13:47:22 +03:00
|
|
|
static int
|
2016-05-04 12:11:59 +03:00
|
|
|
i9xx_select_p2_div(const struct intel_limit *limit,
|
2015-06-18 13:47:22 +03:00
|
|
|
const struct intel_crtc_state *crtc_state,
|
|
|
|
|
int target)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2015-06-18 13:47:22 +03:00
|
|
|
struct drm_device *dev = crtc_state->base.crtc->dev;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/*
|
2012-11-26 17:22:08 +01:00
|
|
|
* For LVDS just rely on its current settings for dual-channel.
|
|
|
|
|
* We haven't figured out how to reliably set up different
|
|
|
|
|
* single/dual channel state, if we even can.
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
*/
|
2012-11-26 17:22:09 +01:00
|
|
|
if (intel_is_dual_link_lvds(dev))
|
2015-06-18 13:47:22 +03:00
|
|
|
return limit->p2.p2_fast;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
else
|
2015-06-18 13:47:22 +03:00
|
|
|
return limit->p2.p2_slow;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
} else {
|
|
|
|
|
if (target < limit->p2.dot_limit)
|
2015-06-18 13:47:22 +03:00
|
|
|
return limit->p2.p2_slow;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
else
|
2015-06-18 13:47:22 +03:00
|
|
|
return limit->p2.p2_fast;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
2015-06-18 13:47:22 +03:00
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:16 +02:00
|
|
|
/*
|
|
|
|
|
* Returns a set of divisors for the desired target clock with the given
|
|
|
|
|
* refclk, or FALSE. The returned values represent the clock equation:
|
|
|
|
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
|
|
|
|
*
|
|
|
|
|
* Target and reference clocks are specified in kHz.
|
|
|
|
|
*
|
|
|
|
|
* If match_clock is provided, then best_clock P divider must match the P
|
|
|
|
|
* divider from @match_clock used for LVDS downclocking.
|
|
|
|
|
*/
|
2015-06-18 13:47:22 +03:00
|
|
|
static bool
|
2016-05-04 12:11:59 +03:00
|
|
|
i9xx_find_best_dpll(const struct intel_limit *limit,
|
2015-06-18 13:47:22 +03:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
int target, int refclk, struct dpll *match_clock,
|
|
|
|
|
struct dpll *best_clock)
|
2015-06-18 13:47:22 +03:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc_state->base.crtc->dev;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2015-06-18 13:47:22 +03:00
|
|
|
int err = target;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2011-08-16 15:34:10 -04:00
|
|
|
memset(best_clock, 0, sizeof(*best_clock));
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2015-06-18 13:47:22 +03:00
|
|
|
clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
|
|
|
|
|
|
2009-11-20 11:24:18 +08:00
|
|
|
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
|
|
|
|
|
clock.m1++) {
|
|
|
|
|
for (clock.m2 = limit->m2.min;
|
|
|
|
|
clock.m2 <= limit->m2.max; clock.m2++) {
|
2013-06-03 20:56:24 +02:00
|
|
|
if (clock.m2 >= clock.m1)
|
2009-11-20 11:24:18 +08:00
|
|
|
break;
|
|
|
|
|
for (clock.n = limit->n.min;
|
|
|
|
|
clock.n <= limit->n.max; clock.n++) {
|
|
|
|
|
for (clock.p1 = limit->p1.min;
|
|
|
|
|
clock.p1 <= limit->p1.max; clock.p1++) {
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
int this_err;
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
i9xx_calc_dpll_params(refclk, &clock);
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!intel_PLL_is_valid(to_i915(dev),
|
|
|
|
|
limit,
|
2013-06-01 17:16:17 +02:00
|
|
|
&clock))
|
|
|
|
|
continue;
|
|
|
|
|
if (match_clock &&
|
|
|
|
|
clock.p != match_clock->p)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
this_err = abs(clock.dot - target);
|
|
|
|
|
if (this_err < err) {
|
|
|
|
|
*best_clock = clock;
|
|
|
|
|
err = this_err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (err != target);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:16 +02:00
|
|
|
/*
|
|
|
|
|
* Returns a set of divisors for the desired target clock with the given
|
|
|
|
|
* refclk, or FALSE. The returned values represent the clock equation:
|
|
|
|
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
|
|
|
|
*
|
|
|
|
|
* Target and reference clocks are specified in kHz.
|
|
|
|
|
*
|
|
|
|
|
* If match_clock is provided, then best_clock P divider must match the P
|
|
|
|
|
* divider from @match_clock used for LVDS downclocking.
|
|
|
|
|
*/
|
2013-06-01 17:16:17 +02:00
|
|
|
static bool
|
2016-05-04 12:11:59 +03:00
|
|
|
pnv_find_best_dpll(const struct intel_limit *limit,
|
2015-03-20 16:18:17 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
int target, int refclk, struct dpll *match_clock,
|
|
|
|
|
struct dpll *best_clock)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2015-06-18 13:47:22 +03:00
|
|
|
struct drm_device *dev = crtc_state->base.crtc->dev;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
int err = target;
|
|
|
|
|
|
2011-08-16 15:34:10 -04:00
|
|
|
memset(best_clock, 0, sizeof(*best_clock));
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2015-06-18 13:47:22 +03:00
|
|
|
clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
|
|
|
|
|
|
2009-11-20 11:24:18 +08:00
|
|
|
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
|
|
|
|
|
clock.m1++) {
|
|
|
|
|
for (clock.m2 = limit->m2.min;
|
|
|
|
|
clock.m2 <= limit->m2.max; clock.m2++) {
|
|
|
|
|
for (clock.n = limit->n.min;
|
|
|
|
|
clock.n <= limit->n.max; clock.n++) {
|
|
|
|
|
for (clock.p1 = limit->p1.min;
|
|
|
|
|
clock.p1 <= limit->p1.max; clock.p1++) {
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
int this_err;
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
pnv_calc_dpll_params(refclk, &clock);
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!intel_PLL_is_valid(to_i915(dev),
|
|
|
|
|
limit,
|
2010-12-14 20:04:54 +00:00
|
|
|
&clock))
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
continue;
|
2012-01-10 15:09:36 -08:00
|
|
|
if (match_clock &&
|
|
|
|
|
clock.p != match_clock->p)
|
|
|
|
|
continue;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
|
|
|
|
this_err = abs(clock.dot - target);
|
|
|
|
|
if (this_err < err) {
|
|
|
|
|
*best_clock = clock;
|
|
|
|
|
err = this_err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (err != target);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:12 +02:00
|
|
|
/*
|
|
|
|
|
* Returns a set of divisors for the desired target clock with the given
|
|
|
|
|
* refclk, or FALSE. The returned values represent the clock equation:
|
|
|
|
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
2016-03-21 18:00:16 +02:00
|
|
|
*
|
|
|
|
|
* Target and reference clocks are specified in kHz.
|
|
|
|
|
*
|
|
|
|
|
* If match_clock is provided, then best_clock P divider must match the P
|
|
|
|
|
* divider from @match_clock used for LVDS downclocking.
|
2016-03-21 18:00:12 +02:00
|
|
|
*/
|
2009-03-18 20:13:27 +08:00
|
|
|
static bool
|
2016-05-04 12:11:59 +03:00
|
|
|
g4x_find_best_dpll(const struct intel_limit *limit,
|
2015-03-20 16:18:17 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
int target, int refclk, struct dpll *match_clock,
|
|
|
|
|
struct dpll *best_clock)
|
2009-03-18 20:13:27 +08:00
|
|
|
{
|
2015-06-18 13:47:22 +03:00
|
|
|
struct drm_device *dev = crtc_state->base.crtc->dev;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2009-03-18 20:13:27 +08:00
|
|
|
int max_n;
|
2015-06-18 13:47:22 +03:00
|
|
|
bool found = false;
|
2010-07-02 16:43:30 -04:00
|
|
|
/* approximately equals target * 0.00585 */
|
|
|
|
|
int err_most = (target >> 8) + (target >> 9);
|
2009-03-18 20:13:27 +08:00
|
|
|
|
|
|
|
|
memset(best_clock, 0, sizeof(*best_clock));
|
2015-06-18 13:47:22 +03:00
|
|
|
|
|
|
|
|
clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
|
|
|
|
|
|
2009-03-18 20:13:27 +08:00
|
|
|
max_n = limit->n.max;
|
2010-03-29 15:41:47 +02:00
|
|
|
/* based on hardware requirement, prefer smaller n to precision */
|
2009-03-18 20:13:27 +08:00
|
|
|
for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
|
2010-03-29 15:41:47 +02:00
|
|
|
/* based on hardware requirement, prefere larger m1,m2 */
|
2009-03-18 20:13:27 +08:00
|
|
|
for (clock.m1 = limit->m1.max;
|
|
|
|
|
clock.m1 >= limit->m1.min; clock.m1--) {
|
|
|
|
|
for (clock.m2 = limit->m2.max;
|
|
|
|
|
clock.m2 >= limit->m2.min; clock.m2--) {
|
|
|
|
|
for (clock.p1 = limit->p1.max;
|
|
|
|
|
clock.p1 >= limit->p1.min; clock.p1--) {
|
|
|
|
|
int this_err;
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
i9xx_calc_dpll_params(refclk, &clock);
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!intel_PLL_is_valid(to_i915(dev),
|
|
|
|
|
limit,
|
2010-12-14 20:04:54 +00:00
|
|
|
&clock))
|
2009-03-18 20:13:27 +08:00
|
|
|
continue;
|
2010-12-14 20:04:54 +00:00
|
|
|
|
|
|
|
|
this_err = abs(clock.dot - target);
|
2009-03-18 20:13:27 +08:00
|
|
|
if (this_err < err_most) {
|
|
|
|
|
*best_clock = clock;
|
|
|
|
|
err_most = this_err;
|
|
|
|
|
max_n = clock.n;
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-05 15:38:42 +08:00
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 11:40:03 +02:00
|
|
|
/*
|
|
|
|
|
* Check if the calculated PLL configuration is more optimal compared to the
|
|
|
|
|
* best configuration and error found so far. Return the calculated error.
|
|
|
|
|
*/
|
|
|
|
|
static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
|
2016-05-04 12:11:57 +03:00
|
|
|
const struct dpll *calculated_clock,
|
|
|
|
|
const struct dpll *best_clock,
|
2015-03-17 11:40:03 +02:00
|
|
|
unsigned int best_error_ppm,
|
|
|
|
|
unsigned int *error_ppm)
|
|
|
|
|
{
|
2015-03-17 11:40:05 +02:00
|
|
|
/*
|
|
|
|
|
* For CHV ignore the error and consider only the P value.
|
|
|
|
|
* Prefer a bigger P value based on HW requirements.
|
|
|
|
|
*/
|
2016-10-14 10:13:44 +01:00
|
|
|
if (IS_CHERRYVIEW(to_i915(dev))) {
|
2015-03-17 11:40:05 +02:00
|
|
|
*error_ppm = 0;
|
|
|
|
|
|
|
|
|
|
return calculated_clock->p > best_clock->p;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 11:40:04 +02:00
|
|
|
if (WARN_ON_ONCE(!target_freq))
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-03-17 11:40:03 +02:00
|
|
|
*error_ppm = div_u64(1000000ULL *
|
|
|
|
|
abs(target_freq - calculated_clock->dot),
|
|
|
|
|
target_freq);
|
|
|
|
|
/*
|
|
|
|
|
* Prefer a better P value over a better (smaller) error if the error
|
|
|
|
|
* is small. Ensure this preference for future configurations too by
|
|
|
|
|
* setting the error to 0.
|
|
|
|
|
*/
|
|
|
|
|
if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
|
|
|
|
|
*error_ppm = 0;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *error_ppm + 10 < best_error_ppm;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:13 +02:00
|
|
|
/*
|
|
|
|
|
* Returns a set of divisors for the desired target clock with the given
|
|
|
|
|
* refclk, or FALSE. The returned values represent the clock equation:
|
|
|
|
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
|
|
|
|
*/
|
2012-06-15 11:55:13 -07:00
|
|
|
static bool
|
2016-05-04 12:11:59 +03:00
|
|
|
vlv_find_best_dpll(const struct intel_limit *limit,
|
2015-03-20 16:18:17 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
int target, int refclk, struct dpll *match_clock,
|
|
|
|
|
struct dpll *best_clock)
|
2012-06-15 11:55:13 -07:00
|
|
|
{
|
2015-03-20 16:18:17 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
2014-10-20 13:46:43 +03:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2013-09-24 21:26:20 +03:00
|
|
|
unsigned int bestppm = 1000000;
|
2013-09-24 21:26:24 +03:00
|
|
|
/* min update 19.2 MHz */
|
|
|
|
|
int max_n = min(limit->n.max, refclk / 19200);
|
2013-09-24 21:26:31 +03:00
|
|
|
bool found = false;
|
2012-06-15 11:55:13 -07:00
|
|
|
|
2013-09-27 16:54:19 +03:00
|
|
|
target *= 5; /* fast clock */
|
|
|
|
|
|
|
|
|
|
memset(best_clock, 0, sizeof(*best_clock));
|
2012-06-15 11:55:13 -07:00
|
|
|
|
|
|
|
|
/* based on hardware requirement, prefer smaller n to precision */
|
2013-09-24 21:26:24 +03:00
|
|
|
for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
|
2013-09-24 21:26:25 +03:00
|
|
|
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
|
2013-09-24 21:26:27 +03:00
|
|
|
for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
|
2013-09-24 21:26:23 +03:00
|
|
|
clock.p2 -= clock.p2 > 10 ? 2 : 1) {
|
2013-09-27 16:54:19 +03:00
|
|
|
clock.p = clock.p1 * clock.p2;
|
2012-06-15 11:55:13 -07:00
|
|
|
/* based on hardware requirement, prefer bigger m1,m2 values */
|
2013-09-27 16:54:19 +03:00
|
|
|
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
|
2015-03-17 11:40:03 +02:00
|
|
|
unsigned int ppm;
|
2013-09-24 21:26:20 +03:00
|
|
|
|
2013-09-27 16:54:19 +03:00
|
|
|
clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
|
|
|
|
|
refclk * clock.m1);
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
vlv_calc_dpll_params(refclk, &clock);
|
2013-09-24 21:26:18 +03:00
|
|
|
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!intel_PLL_is_valid(to_i915(dev),
|
|
|
|
|
limit,
|
2013-09-27 16:55:49 +03:00
|
|
|
&clock))
|
2013-09-24 21:26:18 +03:00
|
|
|
continue;
|
|
|
|
|
|
2015-03-17 11:40:03 +02:00
|
|
|
if (!vlv_PLL_is_optimal(dev, target,
|
|
|
|
|
&clock,
|
|
|
|
|
best_clock,
|
|
|
|
|
bestppm, &ppm))
|
|
|
|
|
continue;
|
2013-09-27 16:54:19 +03:00
|
|
|
|
2015-03-17 11:40:03 +02:00
|
|
|
*best_clock = clock;
|
|
|
|
|
bestppm = ppm;
|
|
|
|
|
found = true;
|
2012-06-15 11:55:13 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-24 21:26:31 +03:00
|
|
|
return found;
|
2012-06-15 11:55:13 -07:00
|
|
|
}
|
2009-04-07 16:16:42 -07:00
|
|
|
|
2016-03-21 18:00:13 +02:00
|
|
|
/*
|
|
|
|
|
* Returns a set of divisors for the desired target clock with the given
|
|
|
|
|
* refclk, or FALSE. The returned values represent the clock equation:
|
|
|
|
|
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
|
|
|
|
|
*/
|
2014-04-09 13:28:18 +03:00
|
|
|
static bool
|
2016-05-04 12:11:59 +03:00
|
|
|
chv_find_best_dpll(const struct intel_limit *limit,
|
2015-03-20 16:18:17 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
int target, int refclk, struct dpll *match_clock,
|
|
|
|
|
struct dpll *best_clock)
|
2014-04-09 13:28:18 +03:00
|
|
|
{
|
2015-03-20 16:18:17 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
2014-10-20 13:46:43 +03:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2015-03-17 11:40:05 +02:00
|
|
|
unsigned int best_error_ppm;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2014-04-09 13:28:18 +03:00
|
|
|
uint64_t m2;
|
|
|
|
|
int found = false;
|
|
|
|
|
|
|
|
|
|
memset(best_clock, 0, sizeof(*best_clock));
|
2015-03-17 11:40:05 +02:00
|
|
|
best_error_ppm = 1000000;
|
2014-04-09 13:28:18 +03:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Based on hardware doc, the n always set to 1, and m1 always
|
|
|
|
|
* set to 2. If requires to support 200Mhz refclk, we need to
|
|
|
|
|
* revisit this because n may not 1 anymore.
|
|
|
|
|
*/
|
|
|
|
|
clock.n = 1, clock.m1 = 2;
|
|
|
|
|
target *= 5; /* fast clock */
|
|
|
|
|
|
|
|
|
|
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
|
|
|
|
|
for (clock.p2 = limit->p2.p2_fast;
|
|
|
|
|
clock.p2 >= limit->p2.p2_slow;
|
|
|
|
|
clock.p2 -= clock.p2 > 10 ? 2 : 1) {
|
2015-03-17 11:40:05 +02:00
|
|
|
unsigned int error_ppm;
|
2014-04-09 13:28:18 +03:00
|
|
|
|
|
|
|
|
clock.p = clock.p1 * clock.p2;
|
|
|
|
|
|
|
|
|
|
m2 = DIV_ROUND_CLOSEST_ULL(((uint64_t)target * clock.p *
|
|
|
|
|
clock.n) << 22, refclk * clock.m1);
|
|
|
|
|
|
|
|
|
|
if (m2 > INT_MAX/clock.m1)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
clock.m2 = m2;
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
chv_calc_dpll_params(refclk, &clock);
|
2014-04-09 13:28:18 +03:00
|
|
|
|
2016-10-13 11:03:04 +01:00
|
|
|
if (!intel_PLL_is_valid(to_i915(dev), limit, &clock))
|
2014-04-09 13:28:18 +03:00
|
|
|
continue;
|
|
|
|
|
|
2015-03-17 11:40:05 +02:00
|
|
|
if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
|
|
|
|
|
best_error_ppm, &error_ppm))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
*best_clock = clock;
|
|
|
|
|
best_error_ppm = error_ppm;
|
|
|
|
|
found = true;
|
2014-04-09 13:28:18 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 03:29:25 +02:00
|
|
|
bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock,
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll *best_clock)
|
2015-03-06 03:29:25 +02:00
|
|
|
{
|
2016-03-21 18:00:13 +02:00
|
|
|
int refclk = 100000;
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit = &intel_limits_bxt;
|
2015-03-06 03:29:25 +02:00
|
|
|
|
2016-03-21 18:00:13 +02:00
|
|
|
return chv_find_best_dpll(limit, crtc_state,
|
2015-03-06 03:29:25 +02:00
|
|
|
target_clock, refclk, NULL, best_clock);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-31 22:37:02 +02:00
|
|
|
bool intel_crtc_active(struct intel_crtc *crtc)
|
2013-09-04 18:25:25 +03:00
|
|
|
{
|
|
|
|
|
/* Be paranoid as we can arrive here with only partial
|
|
|
|
|
* state retrieved from the hardware during setup.
|
|
|
|
|
*
|
2013-09-25 16:45:37 +01:00
|
|
|
* We can ditch the adjusted_mode.crtc_clock check as soon
|
2013-09-04 18:25:25 +03:00
|
|
|
* as Haswell has gained clock readout/fastboot support.
|
|
|
|
|
*
|
2014-04-03 07:51:54 +10:00
|
|
|
* We can ditch the crtc->primary->fb check as soon as we can
|
2013-09-04 18:25:25 +03:00
|
|
|
* properly reconstruct framebuffers.
|
2015-03-09 10:19:23 -07:00
|
|
|
*
|
|
|
|
|
* FIXME: The intel_crtc->active here should be switched to
|
|
|
|
|
* crtc->state->active once we have proper CRTC states wired up
|
|
|
|
|
* for atomic.
|
2013-09-04 18:25:25 +03:00
|
|
|
*/
|
2016-10-31 22:37:02 +02:00
|
|
|
return crtc->active && crtc->base.primary->state->fb &&
|
|
|
|
|
crtc->config->base.adjusted_mode.crtc_clock;
|
2013-09-04 18:25:25 +03:00
|
|
|
}
|
|
|
|
|
|
drm/i915: add TRANSCODER_EDP
Before Haswell we used to have the CPU pipes and the PCH transcoders.
We had the same amount of pipes and transcoders, and there was a 1:1
mapping between them. After Haswell what we used to call CPU pipe was
split into CPU pipe and CPU transcoder. So now we have 3 CPU pipes (A,
B and C), 4 CPU transcoders (A, B, C and EDP) and 1 PCH transcoder
(only used for VGA).
For all the outputs except for EDP we have an 1:1 mapping on the CPU
pipes and CPU transcoders, so if you're using CPU pipe A you have to
use CPU transcoder A. When have an eDP output you have to use
transcoder EDP and you can attach this CPU transcoder to any of the 3
CPU pipes. When using VGA you need to select a pair of matching CPU
pipes/transcoders (A/A, B/B, C/C) and you also need to enable/use the
PCH transcoder.
For now we're just creating the cpu_transcoder definitions and setting
cpu_transcoder to TRANSCODER_EDP on DDI eDP code, but none of the
registers was ported to use transcoder instead of pipe. The goal is to
keep the code backwards-compatible since on all cases except when
using eDP we must have pipe == cpu_transcoder.
V2: Comment the haswell_crtc_off chunk, suggested by Damien Lespiau
and Daniel Vetter.
We currently need the haswell_crtc_off chunk because TRANSCODER_EDP
can be used by any CRTC, so when you stop using it you have to stop
saying you're using it, otherwise you may have at some point 2 CRTCs
claiming they're using TRANSCODER_EDP (a disabled CRTC and an enabled
one), then the HW state readout code will get completely confused.
In other words:
Imagine the following case:
xrandr --output eDP1 --auto --crtc 0
xrandr --output eDP1 --off
xrandr --output eDP1 --auto --crtc 2
After the last command you could get a "pipe A assertion failure
(expected off, current on)" because CRTC 0 still claims it's using
TRANSCODER_EDP, so the HW state readout function will read it
(through PIPECONF) and expect it to be off, when it's actually on
because it's being used by CRTC 2.
So when we make "intel_crtc->cpu_transcoder = intel_crtc->pipe" we
make sure we're pointing to our own original CRTC which is certainly
not used by any other CRTC.
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-10-24 15:59:34 -02:00
|
|
|
enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
|
|
|
|
{
|
2016-10-31 22:37:10 +02:00
|
|
|
struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
drm/i915: add TRANSCODER_EDP
Before Haswell we used to have the CPU pipes and the PCH transcoders.
We had the same amount of pipes and transcoders, and there was a 1:1
mapping between them. After Haswell what we used to call CPU pipe was
split into CPU pipe and CPU transcoder. So now we have 3 CPU pipes (A,
B and C), 4 CPU transcoders (A, B, C and EDP) and 1 PCH transcoder
(only used for VGA).
For all the outputs except for EDP we have an 1:1 mapping on the CPU
pipes and CPU transcoders, so if you're using CPU pipe A you have to
use CPU transcoder A. When have an eDP output you have to use
transcoder EDP and you can attach this CPU transcoder to any of the 3
CPU pipes. When using VGA you need to select a pair of matching CPU
pipes/transcoders (A/A, B/B, C/C) and you also need to enable/use the
PCH transcoder.
For now we're just creating the cpu_transcoder definitions and setting
cpu_transcoder to TRANSCODER_EDP on DDI eDP code, but none of the
registers was ported to use transcoder instead of pipe. The goal is to
keep the code backwards-compatible since on all cases except when
using eDP we must have pipe == cpu_transcoder.
V2: Comment the haswell_crtc_off chunk, suggested by Damien Lespiau
and Daniel Vetter.
We currently need the haswell_crtc_off chunk because TRANSCODER_EDP
can be used by any CRTC, so when you stop using it you have to stop
saying you're using it, otherwise you may have at some point 2 CRTCs
claiming they're using TRANSCODER_EDP (a disabled CRTC and an enabled
one), then the HW state readout code will get completely confused.
In other words:
Imagine the following case:
xrandr --output eDP1 --auto --crtc 0
xrandr --output eDP1 --off
xrandr --output eDP1 --auto --crtc 2
After the last command you could get a "pipe A assertion failure
(expected off, current on)" because CRTC 0 still claims it's using
TRANSCODER_EDP, so the HW state readout function will read it
(through PIPECONF) and expect it to be off, when it's actually on
because it's being used by CRTC 2.
So when we make "intel_crtc->cpu_transcoder = intel_crtc->pipe" we
make sure we're pointing to our own original CRTC which is certainly
not used by any other CRTC.
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-10-24 15:59:34 -02:00
|
|
|
|
2016-10-31 22:37:05 +02:00
|
|
|
return crtc->config->cpu_transcoder;
|
drm/i915: add TRANSCODER_EDP
Before Haswell we used to have the CPU pipes and the PCH transcoders.
We had the same amount of pipes and transcoders, and there was a 1:1
mapping between them. After Haswell what we used to call CPU pipe was
split into CPU pipe and CPU transcoder. So now we have 3 CPU pipes (A,
B and C), 4 CPU transcoders (A, B, C and EDP) and 1 PCH transcoder
(only used for VGA).
For all the outputs except for EDP we have an 1:1 mapping on the CPU
pipes and CPU transcoders, so if you're using CPU pipe A you have to
use CPU transcoder A. When have an eDP output you have to use
transcoder EDP and you can attach this CPU transcoder to any of the 3
CPU pipes. When using VGA you need to select a pair of matching CPU
pipes/transcoders (A/A, B/B, C/C) and you also need to enable/use the
PCH transcoder.
For now we're just creating the cpu_transcoder definitions and setting
cpu_transcoder to TRANSCODER_EDP on DDI eDP code, but none of the
registers was ported to use transcoder instead of pipe. The goal is to
keep the code backwards-compatible since on all cases except when
using eDP we must have pipe == cpu_transcoder.
V2: Comment the haswell_crtc_off chunk, suggested by Damien Lespiau
and Daniel Vetter.
We currently need the haswell_crtc_off chunk because TRANSCODER_EDP
can be used by any CRTC, so when you stop using it you have to stop
saying you're using it, otherwise you may have at some point 2 CRTCs
claiming they're using TRANSCODER_EDP (a disabled CRTC and an enabled
one), then the HW state readout code will get completely confused.
In other words:
Imagine the following case:
xrandr --output eDP1 --auto --crtc 0
xrandr --output eDP1 --off
xrandr --output eDP1 --auto --crtc 2
After the last command you could get a "pipe A assertion failure
(expected off, current on)" because CRTC 0 still claims it's using
TRANSCODER_EDP, so the HW state readout function will read it
(through PIPECONF) and expect it to be off, when it's actually on
because it's being used by CRTC 2.
So when we make "intel_crtc->cpu_transcoder = intel_crtc->pipe" we
make sure we're pointing to our own original CRTC which is certainly
not used by any other CRTC.
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-10-24 15:59:34 -02:00
|
|
|
}
|
|
|
|
|
|
2017-11-29 17:37:30 +02:00
|
|
|
static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
2013-10-11 14:21:31 +03:00
|
|
|
{
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg = PIPEDSL(pipe);
|
2013-10-11 14:21:31 +03:00
|
|
|
u32 line1, line2;
|
|
|
|
|
u32 line_mask;
|
|
|
|
|
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN2(dev_priv))
|
2013-10-11 14:21:31 +03:00
|
|
|
line_mask = DSL_LINEMASK_GEN2;
|
|
|
|
|
else
|
|
|
|
|
line_mask = DSL_LINEMASK_GEN3;
|
|
|
|
|
|
|
|
|
|
line1 = I915_READ(reg) & line_mask;
|
2015-07-07 09:10:40 +02:00
|
|
|
msleep(5);
|
2013-10-11 14:21:31 +03:00
|
|
|
line2 = I915_READ(reg) & line_mask;
|
|
|
|
|
|
2017-11-29 17:37:30 +02:00
|
|
|
return line1 != line2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
enum pipe pipe = crtc->pipe;
|
|
|
|
|
|
|
|
|
|
/* Wait for the display line to settle/start moving */
|
|
|
|
|
if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100))
|
|
|
|
|
DRM_ERROR("pipe %c scanline %s wait timed out\n",
|
|
|
|
|
pipe_name(pipe), onoff(state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
wait_for_pipe_scanline_moving(crtc, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
wait_for_pipe_scanline_moving(crtc, true);
|
2013-10-11 14:21:31 +03:00
|
|
|
}
|
|
|
|
|
|
2017-11-29 17:37:32 +02:00
|
|
|
static void
|
|
|
|
|
intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state)
|
2010-08-18 13:20:54 -07:00
|
|
|
{
|
2017-11-29 17:37:32 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2010-10-03 00:33:06 -07:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2017-11-29 17:37:32 +02:00
|
|
|
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg = PIPECONF(cpu_transcoder);
|
2010-10-03 00:33:06 -07:00
|
|
|
|
|
|
|
|
/* Wait for the Pipe State to go off */
|
2016-06-30 15:32:53 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
reg, I965_PIPECONF_ACTIVE, 0,
|
|
|
|
|
100))
|
2012-07-09 09:51:57 +02:00
|
|
|
WARN(1, "pipe_off wait timed out\n");
|
2010-10-03 00:33:06 -07:00
|
|
|
} else {
|
2017-11-29 17:37:30 +02:00
|
|
|
intel_wait_for_pipe_scanline_stopped(crtc);
|
2010-10-03 00:33:06 -07:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2011-01-04 15:09:30 -08:00
|
|
|
/* Only for pre-ILK configs */
|
2013-06-16 21:42:39 +02:00
|
|
|
void assert_pll(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, bool state)
|
2011-01-04 15:09:30 -08:00
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
bool cur_state;
|
|
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(DPLL(pipe));
|
2011-01-04 15:09:30 -08:00
|
|
|
cur_state = !!(val & DPLL_VCO_ENABLE);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2011-01-04 15:09:30 -08:00
|
|
|
"PLL state assertion failure (expected %s, current %s)\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(state), onoff(cur_state));
|
2011-01-04 15:09:30 -08:00
|
|
|
}
|
|
|
|
|
|
2013-08-27 15:12:22 +03:00
|
|
|
/* XXX: the dsi pll is shared between MIPI DSI ports */
|
2016-03-16 10:57:14 +00:00
|
|
|
void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
|
2013-08-27 15:12:22 +03:00
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
bool cur_state;
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2013-08-27 15:12:22 +03:00
|
|
|
val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2013-08-27 15:12:22 +03:00
|
|
|
|
|
|
|
|
cur_state = val & DSI_PLL_VCO_EN;
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2013-08-27 15:12:22 +03:00
|
|
|
"DSI PLL state assertion failure (expected %s, current %s)\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(state), onoff(cur_state));
|
2013-08-27 15:12:22 +03:00
|
|
|
}
|
|
|
|
|
|
2011-01-03 12:14:26 -08:00
|
|
|
static void assert_fdi_tx(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, bool state)
|
|
|
|
|
{
|
|
|
|
|
bool cur_state;
|
2012-10-24 16:06:19 -02:00
|
|
|
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
|
|
|
|
pipe);
|
2011-01-03 12:14:26 -08:00
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_DDI(dev_priv)) {
|
2012-11-23 15:30:39 -02:00
|
|
|
/* DDI does not have a specific FDI_TX register */
|
2015-09-22 19:50:01 +03:00
|
|
|
u32 val = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
2012-10-24 16:06:19 -02:00
|
|
|
cur_state = !!(val & TRANS_DDI_FUNC_ENABLE);
|
2012-05-09 15:37:18 -03:00
|
|
|
} else {
|
2015-09-22 19:50:01 +03:00
|
|
|
u32 val = I915_READ(FDI_TX_CTL(pipe));
|
2012-05-09 15:37:18 -03:00
|
|
|
cur_state = !!(val & FDI_TX_ENABLE);
|
|
|
|
|
}
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2011-01-03 12:14:26 -08:00
|
|
|
"FDI TX state assertion failure (expected %s, current %s)\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(state), onoff(cur_state));
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true)
|
|
|
|
|
#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false)
|
|
|
|
|
|
|
|
|
|
static void assert_fdi_rx(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, bool state)
|
|
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
bool cur_state;
|
|
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(FDI_RX_CTL(pipe));
|
2012-11-20 13:27:35 -02:00
|
|
|
cur_state = !!(val & FDI_RX_ENABLE);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2011-01-03 12:14:26 -08:00
|
|
|
"FDI RX state assertion failure (expected %s, current %s)\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(state), onoff(cur_state));
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true)
|
|
|
|
|
#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false)
|
|
|
|
|
|
|
|
|
|
static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
|
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
|
|
/* ILK FDI PLL is always enabled */
|
2016-05-10 10:57:06 +01:00
|
|
|
if (IS_GEN5(dev_priv))
|
2011-01-03 12:14:26 -08:00
|
|
|
return;
|
|
|
|
|
|
2012-05-09 15:37:18 -03:00
|
|
|
/* On Haswell, DDI ports are responsible for the FDI PLL setup */
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_DDI(dev_priv))
|
2012-05-09 15:37:18 -03:00
|
|
|
return;
|
|
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(FDI_TX_CTL(pipe));
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
|
2013-06-16 21:42:39 +02:00
|
|
|
void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, bool state)
|
2011-01-03 12:14:26 -08:00
|
|
|
{
|
|
|
|
|
u32 val;
|
2013-06-16 21:42:39 +02:00
|
|
|
bool cur_state;
|
2011-01-03 12:14:26 -08:00
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(FDI_RX_CTL(pipe));
|
2013-06-16 21:42:39 +02:00
|
|
|
cur_state = !!(val & FDI_RX_PLL_ENABLE);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2013-06-16 21:42:39 +02:00
|
|
|
"FDI RX PLL assertion failure (expected %s, current %s)\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(state), onoff(cur_state));
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe)
|
2011-01-04 15:09:32 -08:00
|
|
|
{
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t pp_reg;
|
2011-01-04 15:09:32 -08:00
|
|
|
u32 val;
|
|
|
|
|
enum pipe panel_pipe = PIPE_A;
|
2011-08-25 15:37:45 +02:00
|
|
|
bool locked = true;
|
2011-01-04 15:09:32 -08:00
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
if (WARN_ON(HAS_DDI(dev_priv)))
|
2014-08-22 15:04:13 +03:00
|
|
|
return;
|
|
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
if (HAS_PCH_SPLIT(dev_priv)) {
|
2014-08-22 15:04:13 +03:00
|
|
|
u32 port_sel;
|
|
|
|
|
|
2016-08-10 14:07:29 +03:00
|
|
|
pp_reg = PP_CONTROL(0);
|
|
|
|
|
port_sel = I915_READ(PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK;
|
2014-08-22 15:04:13 +03:00
|
|
|
|
|
|
|
|
if (port_sel == PANEL_PORT_SELECT_LVDS &&
|
|
|
|
|
I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT)
|
|
|
|
|
panel_pipe = PIPE_B;
|
|
|
|
|
/* XXX: else fix for eDP */
|
2016-10-13 11:02:52 +01:00
|
|
|
} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
|
2014-08-22 15:04:13 +03:00
|
|
|
/* presumably write lock depends on pipe, not port select */
|
2016-08-10 14:07:29 +03:00
|
|
|
pp_reg = PP_CONTROL(pipe);
|
2014-08-22 15:04:13 +03:00
|
|
|
panel_pipe = pipe;
|
2011-01-04 15:09:32 -08:00
|
|
|
} else {
|
2016-08-10 14:07:29 +03:00
|
|
|
pp_reg = PP_CONTROL(0);
|
2014-08-22 15:04:13 +03:00
|
|
|
if (I915_READ(LVDS) & LVDS_PIPEB_SELECT)
|
|
|
|
|
panel_pipe = PIPE_B;
|
2011-01-04 15:09:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = I915_READ(pp_reg);
|
|
|
|
|
if (!(val & PANEL_POWER_ON) ||
|
2014-08-21 15:06:25 +03:00
|
|
|
((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
|
2011-01-04 15:09:32 -08:00
|
|
|
locked = false;
|
|
|
|
|
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(panel_pipe == pipe && locked,
|
2011-01-04 15:09:32 -08:00
|
|
|
"panel assertion failure, pipe %c regs locked\n",
|
2011-02-07 12:26:52 -08:00
|
|
|
pipe_name(pipe));
|
2011-01-04 15:09:32 -08:00
|
|
|
}
|
|
|
|
|
|
2011-12-13 13:19:38 -08:00
|
|
|
void assert_pipe(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, bool state)
|
2011-01-04 15:09:30 -08:00
|
|
|
{
|
2011-01-04 15:09:33 -08:00
|
|
|
bool cur_state;
|
2012-10-23 18:29:59 -02:00
|
|
|
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
|
|
|
|
pipe);
|
2016-02-12 18:55:14 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
2011-01-04 15:09:30 -08:00
|
|
|
|
2017-06-01 17:36:19 +03:00
|
|
|
/* we keep both pipes enabled on 830 */
|
|
|
|
|
if (IS_I830(dev_priv))
|
2012-01-22 01:36:48 +01:00
|
|
|
state = true;
|
|
|
|
|
|
2016-02-12 18:55:14 +02:00
|
|
|
power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
|
|
|
|
|
if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
|
2015-09-22 19:50:01 +03:00
|
|
|
u32 val = I915_READ(PIPECONF(cpu_transcoder));
|
2013-01-29 16:35:19 -02:00
|
|
|
cur_state = !!(val & PIPECONF_ENABLE);
|
2016-02-12 18:55:14 +02:00
|
|
|
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
} else {
|
|
|
|
|
cur_state = false;
|
2013-01-29 16:35:19 -02:00
|
|
|
}
|
|
|
|
|
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2011-01-04 15:09:33 -08:00
|
|
|
"pipe %c assertion failure (expected %s, current %s)\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
pipe_name(pipe), onoff(state), onoff(cur_state));
|
2011-01-04 15:09:30 -08:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
static void assert_plane(struct intel_plane *plane, bool state)
|
2011-01-04 15:09:30 -08:00
|
|
|
{
|
2017-11-17 21:19:08 +02:00
|
|
|
bool cur_state = plane->get_hw_state(plane);
|
2011-01-04 15:09:30 -08:00
|
|
|
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(cur_state != state,
|
2017-11-17 21:19:08 +02:00
|
|
|
"%s assertion failure (expected %s, current %s)\n",
|
|
|
|
|
plane->base.name, onoff(state), onoff(cur_state));
|
2011-01-04 15:09:30 -08:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
#define assert_plane_enabled(p) assert_plane(p, true)
|
|
|
|
|
#define assert_plane_disabled(p) assert_plane(p, false)
|
2012-01-16 23:01:13 +00:00
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
static void assert_planes_disabled(struct intel_crtc *crtc)
|
2011-01-04 15:09:30 -08:00
|
|
|
{
|
2017-11-17 21:19:08 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
struct intel_plane *plane;
|
2013-03-28 09:55:38 -07:00
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane)
|
|
|
|
|
assert_plane_disabled(plane);
|
2013-03-28 09:55:38 -07:00
|
|
|
}
|
|
|
|
|
|
2014-08-06 14:49:45 +03:00
|
|
|
static void assert_vblank_disabled(struct drm_crtc *crtc)
|
|
|
|
|
{
|
2014-12-15 13:56:32 -05:00
|
|
|
if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
|
2014-08-06 14:49:45 +03:00
|
|
|
drm_crtc_vblank_put(crtc);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 17:46:15 +02:00
|
|
|
void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
2011-01-04 15:09:34 -08:00
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
bool enabled;
|
|
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(PCH_TRANSCONF(pipe));
|
2011-01-04 15:09:34 -08:00
|
|
|
enabled = !!(val & TRANS_ENABLE);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(enabled,
|
2011-02-07 12:26:52 -08:00
|
|
|
"transcoder assertion failed, should be off on pipe %c but is still active\n",
|
|
|
|
|
pipe_name(pipe));
|
2011-01-04 15:09:34 -08:00
|
|
|
}
|
|
|
|
|
|
2011-08-06 10:39:45 -07:00
|
|
|
static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, u32 port_sel, u32 val)
|
2011-07-25 22:12:43 -07:00
|
|
|
{
|
|
|
|
|
if ((val & DP_PORT_EN) == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
u32 trans_dp_ctl = I915_READ(TRANS_DP_CTL(pipe));
|
2011-07-25 22:12:43 -07:00
|
|
|
if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel)
|
|
|
|
|
return false;
|
2016-04-07 11:08:05 +03:00
|
|
|
} else if (IS_CHERRYVIEW(dev_priv)) {
|
2014-04-09 13:28:21 +03:00
|
|
|
if ((val & DP_PIPE_MASK_CHV) != DP_PIPE_SELECT_CHV(pipe))
|
|
|
|
|
return false;
|
2011-07-25 22:12:43 -07:00
|
|
|
} else {
|
|
|
|
|
if ((val & DP_PIPE_MASK) != (pipe << 30))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-06 10:35:34 -07:00
|
|
|
static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, u32 val)
|
|
|
|
|
{
|
2013-02-19 16:21:46 -03:00
|
|
|
if ((val & SDVO_ENABLE) == 0)
|
2011-08-06 10:35:34 -07:00
|
|
|
return false;
|
|
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2013-02-19 16:21:46 -03:00
|
|
|
if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe))
|
2011-08-06 10:35:34 -07:00
|
|
|
return false;
|
2016-04-07 11:08:05 +03:00
|
|
|
} else if (IS_CHERRYVIEW(dev_priv)) {
|
2014-04-09 13:28:21 +03:00
|
|
|
if ((val & SDVO_PIPE_SEL_MASK_CHV) != SDVO_PIPE_SEL_CHV(pipe))
|
|
|
|
|
return false;
|
2011-08-06 10:35:34 -07:00
|
|
|
} else {
|
2013-02-19 16:21:46 -03:00
|
|
|
if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe))
|
2011-08-06 10:35:34 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, u32 val)
|
|
|
|
|
{
|
|
|
|
|
if ((val & LVDS_PORT_EN) == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2011-08-06 10:35:34 -07:00
|
|
|
if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, u32 val)
|
|
|
|
|
{
|
|
|
|
|
if ((val & ADPA_DAC_ENABLE) == 0)
|
|
|
|
|
return false;
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2011-08-06 10:35:34 -07:00
|
|
|
if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-02 12:28:03 -08:00
|
|
|
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
enum pipe pipe, i915_reg_t reg,
|
|
|
|
|
u32 port_sel)
|
2011-02-02 12:28:03 -08:00
|
|
|
{
|
2011-02-07 13:46:40 -08:00
|
|
|
u32 val = I915_READ(reg);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
|
2011-02-02 12:28:03 -08:00
|
|
|
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_mmio_reg_offset(reg), pipe_name(pipe));
|
2012-06-05 11:03:40 +02:00
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && (val & DP_PORT_EN) == 0
|
2012-09-10 21:58:29 +02:00
|
|
|
&& (val & DP_PIPEB_SELECT),
|
2012-06-05 11:03:40 +02:00
|
|
|
"IBX PCH dp port still using transcoder B\n");
|
2011-02-02 12:28:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
enum pipe pipe, i915_reg_t reg)
|
2011-02-02 12:28:03 -08:00
|
|
|
{
|
2011-02-07 13:46:40 -08:00
|
|
|
u32 val = I915_READ(reg);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
|
2011-10-07 14:38:43 -04:00
|
|
|
"PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_mmio_reg_offset(reg), pipe_name(pipe));
|
2012-06-05 11:03:40 +02:00
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && (val & SDVO_ENABLE) == 0
|
2012-09-10 21:58:29 +02:00
|
|
|
&& (val & SDVO_PIPE_B_SELECT),
|
2012-06-05 11:03:40 +02:00
|
|
|
"IBX PCH hdmi port still using transcoder B\n");
|
2011-02-02 12:28:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
|
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
|
2011-07-25 22:12:43 -07:00
|
|
|
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
|
|
|
|
|
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
|
|
|
|
|
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
|
2011-02-02 12:28:03 -08:00
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(PCH_ADPA);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val),
|
2011-02-02 12:28:03 -08:00
|
|
|
"PCH VGA enabled on transcoder %c, should be disabled\n",
|
2011-02-07 12:26:52 -08:00
|
|
|
pipe_name(pipe));
|
2011-02-02 12:28:03 -08:00
|
|
|
|
2015-09-22 19:50:01 +03:00
|
|
|
val = I915_READ(PCH_LVDS);
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val),
|
2011-02-02 12:28:03 -08:00
|
|
|
"PCH LVDS enabled on transcoder %c, should be disabled\n",
|
2011-02-07 12:26:52 -08:00
|
|
|
pipe_name(pipe));
|
2011-02-02 12:28:03 -08:00
|
|
|
|
drm/i915: clarify confusion between SDVO and HDMI registers
Some HDMI registers can be used for SDVO, so saying "HDMIB" should be
the same as saying "SDVOB" for a given HW generation. This was not
true and led to confusions and even a regression.
Previously we had:
- SDVO{B,C} defined as the Gen3+ registers
- HDMI{B,C,D} and PCH_SDVOB defined as the PCH registers
But now:
- SDVO{B,C} became GEN3_SDVO{B,C} on SDVO code
- SDVO{B,C} became GEN4_HDMI{B,C} on HDMI code
- HDMI{B,C,D} became PCH_HDMI{B,C,D}
- PCH_SDVOB is still the same thing
v2: Rebase (v1 was sent in May 2012).
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-18 19:00:27 -03:00
|
|
|
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB);
|
|
|
|
|
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC);
|
|
|
|
|
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
|
2011-02-02 12:28:03 -08:00
|
|
|
}
|
|
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
static void _vlv_enable_pll(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
enum pipe pipe = crtc->pipe;
|
|
|
|
|
|
|
|
|
|
I915_WRITE(DPLL(pipe), pipe_config->dpll_hw_state.dpll);
|
|
|
|
|
POSTING_READ(DPLL(pipe));
|
|
|
|
|
udelay(150);
|
|
|
|
|
|
2016-06-30 15:32:54 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
DPLL(pipe),
|
|
|
|
|
DPLL_LOCK_VLV,
|
|
|
|
|
DPLL_LOCK_VLV,
|
|
|
|
|
1))
|
2016-04-12 22:14:34 +03:00
|
|
|
DRM_ERROR("DPLL %d failed to lock\n", pipe);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-28 13:20:22 +02:00
|
|
|
static void vlv_enable_pll(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
const struct intel_crtc_state *pipe_config)
|
2013-06-06 00:52:17 +02:00
|
|
|
{
|
2016-04-12 22:14:34 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2016-03-15 16:39:57 +02:00
|
|
|
enum pipe pipe = crtc->pipe;
|
2013-06-06 00:52:17 +02:00
|
|
|
|
2016-03-15 16:39:57 +02:00
|
|
|
assert_pipe_disabled(dev_priv, pipe);
|
2013-06-06 00:52:17 +02:00
|
|
|
|
|
|
|
|
/* PLL is protected by panel, make sure we can write it */
|
2016-03-15 16:39:58 +02:00
|
|
|
assert_panel_unlocked(dev_priv, pipe);
|
2013-06-06 00:52:17 +02:00
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE)
|
|
|
|
|
_vlv_enable_pll(crtc, pipe_config);
|
2013-07-11 22:13:42 +02:00
|
|
|
|
2016-03-15 16:39:57 +02:00
|
|
|
I915_WRITE(DPLL_MD(pipe), pipe_config->dpll_hw_state.dpll_md);
|
|
|
|
|
POSTING_READ(DPLL_MD(pipe));
|
2013-06-06 00:52:17 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
|
|
|
|
|
static void _chv_enable_pll(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *pipe_config)
|
2014-05-02 14:27:47 +03:00
|
|
|
{
|
2016-04-12 22:14:34 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2016-03-15 16:39:57 +02:00
|
|
|
enum pipe pipe = crtc->pipe;
|
2014-05-02 14:27:47 +03:00
|
|
|
enum dpio_channel port = vlv_pipe_to_channel(pipe);
|
|
|
|
|
u32 tmp;
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2014-05-02 14:27:47 +03:00
|
|
|
|
|
|
|
|
/* Enable back the 10bit clock to display controller */
|
|
|
|
|
tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
|
|
|
|
|
tmp |= DPIO_DCLKP_EN;
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp);
|
|
|
|
|
|
2015-05-26 20:42:31 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
|
|
|
|
|
2014-05-02 14:27:47 +03:00
|
|
|
/*
|
|
|
|
|
* Need to wait > 100ns between dclkp clock enable bit and PLL enable.
|
|
|
|
|
*/
|
|
|
|
|
udelay(1);
|
|
|
|
|
|
|
|
|
|
/* Enable PLL */
|
2014-10-28 13:20:22 +02:00
|
|
|
I915_WRITE(DPLL(pipe), pipe_config->dpll_hw_state.dpll);
|
2014-05-02 14:27:47 +03:00
|
|
|
|
|
|
|
|
/* Check PLL is locked */
|
2016-06-30 15:32:55 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
DPLL(pipe), DPLL_LOCK_VLV, DPLL_LOCK_VLV,
|
|
|
|
|
1))
|
2014-05-02 14:27:47 +03:00
|
|
|
DRM_ERROR("PLL %d failed to lock\n", pipe);
|
2016-04-12 22:14:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void chv_enable_pll(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
enum pipe pipe = crtc->pipe;
|
|
|
|
|
|
|
|
|
|
assert_pipe_disabled(dev_priv, pipe);
|
|
|
|
|
|
|
|
|
|
/* PLL is protected by panel, make sure we can write it */
|
|
|
|
|
assert_panel_unlocked(dev_priv, pipe);
|
|
|
|
|
|
|
|
|
|
if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE)
|
|
|
|
|
_chv_enable_pll(crtc, pipe_config);
|
2014-05-02 14:27:47 +03:00
|
|
|
|
2016-03-15 16:39:56 +02:00
|
|
|
if (pipe != PIPE_A) {
|
|
|
|
|
/*
|
|
|
|
|
* WaPixelRepeatModeFixForC0:chv
|
|
|
|
|
*
|
|
|
|
|
* DPLLCMD is AWOL. Use chicken bits to propagate
|
|
|
|
|
* the value from DPLLBMD to either pipe B or C.
|
|
|
|
|
*/
|
2017-09-13 17:08:54 +03:00
|
|
|
I915_WRITE(CBR4_VLV, CBR_DPLLBMD_PIPE(pipe));
|
2016-03-15 16:39:56 +02:00
|
|
|
I915_WRITE(DPLL_MD(PIPE_B), pipe_config->dpll_hw_state.dpll_md);
|
|
|
|
|
I915_WRITE(CBR4_VLV, 0);
|
|
|
|
|
dev_priv->chv_dpll_md[pipe] = pipe_config->dpll_hw_state.dpll_md;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* DPLLB VGA mode also seems to cause problems.
|
|
|
|
|
* We should always have it disabled.
|
|
|
|
|
*/
|
|
|
|
|
WARN_ON((I915_READ(DPLL(PIPE_B)) & DPLL_VGA_MODE_DIS) == 0);
|
|
|
|
|
} else {
|
|
|
|
|
I915_WRITE(DPLL_MD(pipe), pipe_config->dpll_hw_state.dpll_md);
|
|
|
|
|
POSTING_READ(DPLL_MD(pipe));
|
|
|
|
|
}
|
2014-05-02 14:27:47 +03:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
static int intel_num_dvo_pipes(struct drm_i915_private *dev_priv)
|
2014-09-05 21:52:42 +03:00
|
|
|
{
|
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
2015-06-01 12:50:10 +02:00
|
|
|
count += crtc->base.state->active &&
|
2016-06-22 21:57:02 +03:00
|
|
|
intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DVO);
|
|
|
|
|
}
|
2014-09-05 21:52:42 +03:00
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-13 17:08:56 +03:00
|
|
|
static void i9xx_enable_pll(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *crtc_state)
|
2011-01-04 15:09:33 -08:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg = DPLL(crtc->pipe);
|
2017-09-13 17:08:56 +03:00
|
|
|
u32 dpll = crtc_state->dpll_hw_state.dpll;
|
2017-06-01 17:36:15 +03:00
|
|
|
int i;
|
2011-01-04 15:09:33 -08:00
|
|
|
|
2013-06-16 21:24:16 +02:00
|
|
|
assert_pipe_disabled(dev_priv, crtc->pipe);
|
2013-04-11 16:29:09 +02:00
|
|
|
|
2011-01-04 15:09:33 -08:00
|
|
|
/* PLL is protected by panel, make sure we can write it */
|
2016-10-13 11:02:58 +01:00
|
|
|
if (IS_MOBILE(dev_priv) && !IS_I830(dev_priv))
|
2013-06-16 21:24:16 +02:00
|
|
|
assert_panel_unlocked(dev_priv, crtc->pipe);
|
2011-01-04 15:09:33 -08:00
|
|
|
|
2014-09-05 21:52:42 +03:00
|
|
|
/* Enable DVO 2x clock on both PLLs if necessary */
|
2016-11-16 12:32:42 +00:00
|
|
|
if (IS_I830(dev_priv) && intel_num_dvo_pipes(dev_priv) > 0) {
|
2014-09-05 21:52:42 +03:00
|
|
|
/*
|
|
|
|
|
* It appears to be important that we don't enable this
|
|
|
|
|
* for the current pipe before otherwise configuring the
|
|
|
|
|
* PLL. No idea how this should be handled if multiple
|
|
|
|
|
* DVO outputs are enabled simultaneosly.
|
|
|
|
|
*/
|
|
|
|
|
dpll |= DPLL_DVO_2X_MODE;
|
|
|
|
|
I915_WRITE(DPLL(!crtc->pipe),
|
|
|
|
|
I915_READ(DPLL(!crtc->pipe)) | DPLL_DVO_2X_MODE);
|
|
|
|
|
}
|
2013-06-16 21:24:16 +02:00
|
|
|
|
2015-10-07 22:08:25 +03:00
|
|
|
/*
|
|
|
|
|
* Apparently we need to have VGA mode enabled prior to changing
|
|
|
|
|
* the P1/P2 dividers. Otherwise the DPLL will keep using the old
|
|
|
|
|
* dividers, even though the register value does change.
|
|
|
|
|
*/
|
|
|
|
|
I915_WRITE(reg, 0);
|
|
|
|
|
|
2015-10-07 22:08:24 +03:00
|
|
|
I915_WRITE(reg, dpll);
|
|
|
|
|
|
2013-06-16 21:24:16 +02:00
|
|
|
/* Wait for the clocks to stabilize. */
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(150);
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2013-06-16 21:24:16 +02:00
|
|
|
I915_WRITE(DPLL_MD(crtc->pipe),
|
2017-09-13 17:08:56 +03:00
|
|
|
crtc_state->dpll_hw_state.dpll_md);
|
2013-06-16 21:24:16 +02:00
|
|
|
} else {
|
|
|
|
|
/* The pixel multiplier can only be updated once the
|
|
|
|
|
* DPLL is enabled and the clocks are stable.
|
|
|
|
|
*
|
|
|
|
|
* So write it again.
|
|
|
|
|
*/
|
|
|
|
|
I915_WRITE(reg, dpll);
|
|
|
|
|
}
|
2011-01-04 15:09:33 -08:00
|
|
|
|
|
|
|
|
/* We do this three times for luck */
|
2017-06-01 17:36:15 +03:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
|
I915_WRITE(reg, dpll);
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(150); /* wait for warmup */
|
|
|
|
|
}
|
2011-01-04 15:09:33 -08:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 21:52:42 +03:00
|
|
|
static void i9xx_disable_pll(struct intel_crtc *crtc)
|
2011-01-04 15:09:33 -08:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2014-09-05 21:52:42 +03:00
|
|
|
enum pipe pipe = crtc->pipe;
|
|
|
|
|
|
|
|
|
|
/* Disable DVO 2x clock on both PLLs if necessary */
|
2016-10-13 11:02:58 +01:00
|
|
|
if (IS_I830(dev_priv) &&
|
2016-06-22 21:57:02 +03:00
|
|
|
intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DVO) &&
|
2016-11-16 12:32:42 +00:00
|
|
|
!intel_num_dvo_pipes(dev_priv)) {
|
2014-09-05 21:52:42 +03:00
|
|
|
I915_WRITE(DPLL(PIPE_B),
|
|
|
|
|
I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE);
|
|
|
|
|
I915_WRITE(DPLL(PIPE_A),
|
|
|
|
|
I915_READ(DPLL(PIPE_A)) & ~DPLL_DVO_2X_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-15 01:22:07 +03:00
|
|
|
/* Don't disable pipe or pipe PLLs if needed */
|
2017-06-01 17:36:19 +03:00
|
|
|
if (IS_I830(dev_priv))
|
2011-01-04 15:09:33 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Make sure the pipe isn't still relying on us */
|
|
|
|
|
assert_pipe_disabled(dev_priv, pipe);
|
|
|
|
|
|
2015-06-29 15:25:48 +03:00
|
|
|
I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS);
|
2013-06-05 13:34:33 +02:00
|
|
|
POSTING_READ(DPLL(pipe));
|
2011-01-04 15:09:33 -08:00
|
|
|
}
|
|
|
|
|
|
2013-10-01 10:41:38 -07:00
|
|
|
static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|
|
|
|
{
|
2015-06-29 15:25:48 +03:00
|
|
|
u32 val;
|
2013-10-01 10:41:38 -07:00
|
|
|
|
|
|
|
|
/* Make sure the pipe isn't still relying on us */
|
|
|
|
|
assert_pipe_disabled(dev_priv, pipe);
|
|
|
|
|
|
2016-03-15 16:39:55 +02:00
|
|
|
val = DPLL_INTEGRATED_REF_CLK_VLV |
|
|
|
|
|
DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
|
|
|
|
|
if (pipe != PIPE_A)
|
|
|
|
|
val |= DPLL_INTEGRATED_CRI_CLK_VLV;
|
|
|
|
|
|
2013-10-01 10:41:38 -07:00
|
|
|
I915_WRITE(DPLL(pipe), val);
|
|
|
|
|
POSTING_READ(DPLL(pipe));
|
2014-04-09 13:28:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|
|
|
|
{
|
2014-04-09 13:28:59 +03:00
|
|
|
enum dpio_channel port = vlv_pipe_to_channel(pipe);
|
2014-04-09 13:28:17 +03:00
|
|
|
u32 val;
|
|
|
|
|
|
2014-04-09 13:28:57 +03:00
|
|
|
/* Make sure the pipe isn't still relying on us */
|
|
|
|
|
assert_pipe_disabled(dev_priv, pipe);
|
2014-04-09 13:28:17 +03:00
|
|
|
|
2015-06-29 15:25:49 +03:00
|
|
|
val = DPLL_SSC_REF_CLK_CHV |
|
|
|
|
|
DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
|
2014-04-09 13:28:57 +03:00
|
|
|
if (pipe != PIPE_A)
|
|
|
|
|
val |= DPLL_INTEGRATED_CRI_CLK_VLV;
|
2016-03-15 16:39:55 +02:00
|
|
|
|
2014-04-09 13:28:57 +03:00
|
|
|
I915_WRITE(DPLL(pipe), val);
|
|
|
|
|
POSTING_READ(DPLL(pipe));
|
2014-04-09 13:28:59 +03:00
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2014-04-09 13:28:59 +03:00
|
|
|
|
|
|
|
|
/* Disable 10bit clock to display controller */
|
|
|
|
|
val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
|
|
|
|
|
val &= ~DPIO_DCLKP_EN;
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val);
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2013-10-01 10:41:38 -07:00
|
|
|
}
|
|
|
|
|
|
2013-11-06 14:36:35 +08:00
|
|
|
void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
|
2015-04-10 18:21:31 +03:00
|
|
|
struct intel_digital_port *dport,
|
|
|
|
|
unsigned int expected_mask)
|
2013-04-18 14:51:36 -07:00
|
|
|
{
|
|
|
|
|
u32 port_mask;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t dpll_reg;
|
2013-04-18 14:51:36 -07:00
|
|
|
|
2017-11-09 17:24:34 +02:00
|
|
|
switch (dport->base.port) {
|
2013-11-06 14:36:35 +08:00
|
|
|
case PORT_B:
|
2013-04-18 14:51:36 -07:00
|
|
|
port_mask = DPLL_PORTB_READY_MASK;
|
2014-04-09 13:28:15 +03:00
|
|
|
dpll_reg = DPLL(0);
|
2013-11-06 14:36:35 +08:00
|
|
|
break;
|
|
|
|
|
case PORT_C:
|
2013-04-18 14:51:36 -07:00
|
|
|
port_mask = DPLL_PORTC_READY_MASK;
|
2014-04-09 13:28:15 +03:00
|
|
|
dpll_reg = DPLL(0);
|
2015-04-10 18:21:31 +03:00
|
|
|
expected_mask <<= 4;
|
2014-04-09 13:28:15 +03:00
|
|
|
break;
|
|
|
|
|
case PORT_D:
|
|
|
|
|
port_mask = DPLL_PORTD_READY_MASK;
|
|
|
|
|
dpll_reg = DPIO_PHY_STATUS;
|
2013-11-06 14:36:35 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BUG();
|
|
|
|
|
}
|
2013-04-18 14:51:36 -07:00
|
|
|
|
2016-06-30 15:32:56 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
dpll_reg, port_mask, expected_mask,
|
|
|
|
|
1000))
|
2015-04-10 18:21:31 +03:00
|
|
|
WARN(1, "timed out waiting for port %c ready: got 0x%x, expected 0x%x\n",
|
2017-11-09 17:24:34 +02:00
|
|
|
port_name(dport->base.port),
|
|
|
|
|
I915_READ(dpll_reg) & port_mask, expected_mask);
|
2013-04-18 14:51:36 -07:00
|
|
|
}
|
|
|
|
|
|
2012-10-31 18:12:42 -02:00
|
|
|
static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
2011-01-03 12:14:26 -08:00
|
|
|
{
|
2016-10-31 22:37:10 +02:00
|
|
|
struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
|
|
|
|
|
pipe);
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
uint32_t val, pipeconf_val;
|
2011-01-03 12:14:26 -08:00
|
|
|
|
|
|
|
|
/* Make sure PCH DPLL is enabled */
|
2016-03-08 17:46:18 +02:00
|
|
|
assert_shared_dpll_enabled(dev_priv, intel_crtc->config->shared_dpll);
|
2011-01-03 12:14:26 -08:00
|
|
|
|
|
|
|
|
/* FDI must be feeding us bits for PCH ports */
|
|
|
|
|
assert_fdi_tx_enabled(dev_priv, pipe);
|
|
|
|
|
assert_fdi_rx_enabled(dev_priv, pipe);
|
|
|
|
|
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
drm/i915: CPT+ pch transcoder workaround
We need to set the timing override chicken bit after fdi link training
has completed and before we enable the transcoder. We also have to
clear that bit again after disabling the pch transcoder.
See "Graphics BSpec: vol4g North Display Engine Registers [IVB],
Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display
Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI
Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31:
"Workaround : Enable the override prior to enabling the transcoder.
Disable the override after disabling the transcoder."
While at it, use the _PIPE macro for the other TRANS_DP register.
v2: Keep the w/a as-is, but kill the original (but wrongly placed)
workaround introduced in
commit 3bcf603f6d5d18bd9d076dc280de71f48add4101
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Wed Jul 27 11:51:40 2011 -0700
drm/i915: apply timing generator bug workaround on CPT and PPT
and
commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Tue Oct 11 10:43:02 2011 -0700
drm/i915: export a CPT mode set verification function
Note that this old code has unconditionally set the w/a, which might
explain why fdi link training sometimes silently fails, and especially
why the auto-train did not seem to work properly.
v3: Paulo Zanoni pointed out that this workaround is also required on
the LPT PCH. And Arthur Ranyan confirmed that this workaround is
requierd for all ports on the pch, not just DP: The important part
is that the bit is set whenever the pch transcoder is enabled, and
that it is _not_ set while the fdi link is trained. It is also
important that the pch transcoder is fully disabled, i.e. we have to
wait for bit 30 to clear before clearing the w/a bit.
Hence move to workaround into enable/disable_transcoder, where the pch
transcoder gets enabled/disabled.
v4: Whitespace changes dropped.
v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT.
v6:
- resolve conflicts with Paulo's big hsw vga rework
- s/!IBX/CPT since hsw paths are now all separate, and Paulo's patch
to implement the equivalent w/a for LPT is already merged.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Arthur Ranyan <arthur.j.runyan@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v5)
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v5)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-11-01 09:15:30 +01:00
|
|
|
/* Workaround: Set the timing override bit before enabling the
|
|
|
|
|
* pch transcoder. */
|
|
|
|
|
reg = TRANS_CHICKEN2(pipe);
|
|
|
|
|
val = I915_READ(reg);
|
|
|
|
|
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
|
|
|
|
|
I915_WRITE(reg, val);
|
2012-05-09 15:37:19 -03:00
|
|
|
}
|
drm/i915: CPT+ pch transcoder workaround
We need to set the timing override chicken bit after fdi link training
has completed and before we enable the transcoder. We also have to
clear that bit again after disabling the pch transcoder.
See "Graphics BSpec: vol4g North Display Engine Registers [IVB],
Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display
Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI
Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31:
"Workaround : Enable the override prior to enabling the transcoder.
Disable the override after disabling the transcoder."
While at it, use the _PIPE macro for the other TRANS_DP register.
v2: Keep the w/a as-is, but kill the original (but wrongly placed)
workaround introduced in
commit 3bcf603f6d5d18bd9d076dc280de71f48add4101
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Wed Jul 27 11:51:40 2011 -0700
drm/i915: apply timing generator bug workaround on CPT and PPT
and
commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Tue Oct 11 10:43:02 2011 -0700
drm/i915: export a CPT mode set verification function
Note that this old code has unconditionally set the w/a, which might
explain why fdi link training sometimes silently fails, and especially
why the auto-train did not seem to work properly.
v3: Paulo Zanoni pointed out that this workaround is also required on
the LPT PCH. And Arthur Ranyan confirmed that this workaround is
requierd for all ports on the pch, not just DP: The important part
is that the bit is set whenever the pch transcoder is enabled, and
that it is _not_ set while the fdi link is trained. It is also
important that the pch transcoder is fully disabled, i.e. we have to
wait for bit 30 to clear before clearing the w/a bit.
Hence move to workaround into enable/disable_transcoder, where the pch
transcoder gets enabled/disabled.
v4: Whitespace changes dropped.
v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT.
v6:
- resolve conflicts with Paulo's big hsw vga rework
- s/!IBX/CPT since hsw paths are now all separate, and Paulo's patch
to implement the equivalent w/a for LPT is already merged.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Arthur Ranyan <arthur.j.runyan@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v5)
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v5)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-11-01 09:15:30 +01:00
|
|
|
|
2013-05-03 11:49:46 +02:00
|
|
|
reg = PCH_TRANSCONF(pipe);
|
2011-01-03 12:14:26 -08:00
|
|
|
val = I915_READ(reg);
|
2012-02-03 17:47:15 -02:00
|
|
|
pipeconf_val = I915_READ(PIPECONF(pipe));
|
2011-06-24 12:19:20 -07:00
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_IBX(dev_priv)) {
|
2011-06-24 12:19:20 -07:00
|
|
|
/*
|
2015-05-05 17:06:22 +03:00
|
|
|
* Make the BPC in transcoder be consistent with
|
|
|
|
|
* that in pipeconf reg. For HDMI we must use 8bpc
|
|
|
|
|
* here for both 8bpc and 12bpc.
|
2011-06-24 12:19:20 -07:00
|
|
|
*/
|
2012-12-17 11:21:38 +01:00
|
|
|
val &= ~PIPECONF_BPC_MASK;
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_HDMI))
|
2015-05-05 17:06:22 +03:00
|
|
|
val |= PIPECONF_8BPC;
|
|
|
|
|
else
|
|
|
|
|
val |= pipeconf_val & PIPECONF_BPC_MASK;
|
2011-06-24 12:19:20 -07:00
|
|
|
}
|
2012-02-03 17:47:15 -02:00
|
|
|
|
|
|
|
|
val &= ~TRANS_INTERLACE_MASK;
|
|
|
|
|
if ((pipeconf_val & PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK)
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_IBX(dev_priv) &&
|
2016-06-22 21:57:02 +03:00
|
|
|
intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
|
2012-02-14 17:07:09 -02:00
|
|
|
val |= TRANS_LEGACY_INTERLACED_ILK;
|
|
|
|
|
else
|
|
|
|
|
val |= TRANS_INTERLACED;
|
2012-02-03 17:47:15 -02:00
|
|
|
else
|
|
|
|
|
val |= TRANS_PROGRESSIVE;
|
|
|
|
|
|
2011-01-03 12:14:26 -08:00
|
|
|
I915_WRITE(reg, val | TRANS_ENABLE);
|
2016-06-30 15:32:57 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
reg, TRANS_STATE_ENABLE, TRANS_STATE_ENABLE,
|
|
|
|
|
100))
|
2013-04-17 17:48:50 +03:00
|
|
|
DRM_ERROR("failed to enable transcoder %c\n", pipe_name(pipe));
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
|
2012-10-31 18:12:43 -02:00
|
|
|
static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
|
2012-10-31 18:12:47 -02:00
|
|
|
enum transcoder cpu_transcoder)
|
2011-01-03 12:14:26 -08:00
|
|
|
{
|
2012-10-31 18:12:43 -02:00
|
|
|
u32 val, pipeconf_val;
|
|
|
|
|
|
|
|
|
|
/* FDI must be feeding us bits for PCH ports */
|
2012-11-29 22:18:51 +01:00
|
|
|
assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder);
|
2017-07-17 11:14:03 -07:00
|
|
|
assert_fdi_rx_enabled(dev_priv, PIPE_A);
|
2012-10-31 18:12:43 -02:00
|
|
|
|
2012-10-31 18:12:52 -02:00
|
|
|
/* Workaround: set timing override bit. */
|
2015-09-18 20:03:31 +03:00
|
|
|
val = I915_READ(TRANS_CHICKEN2(PIPE_A));
|
drm/i915: CPT+ pch transcoder workaround
We need to set the timing override chicken bit after fdi link training
has completed and before we enable the transcoder. We also have to
clear that bit again after disabling the pch transcoder.
See "Graphics BSpec: vol4g North Display Engine Registers [IVB],
Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display
Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI
Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31:
"Workaround : Enable the override prior to enabling the transcoder.
Disable the override after disabling the transcoder."
While at it, use the _PIPE macro for the other TRANS_DP register.
v2: Keep the w/a as-is, but kill the original (but wrongly placed)
workaround introduced in
commit 3bcf603f6d5d18bd9d076dc280de71f48add4101
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Wed Jul 27 11:51:40 2011 -0700
drm/i915: apply timing generator bug workaround on CPT and PPT
and
commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Tue Oct 11 10:43:02 2011 -0700
drm/i915: export a CPT mode set verification function
Note that this old code has unconditionally set the w/a, which might
explain why fdi link training sometimes silently fails, and especially
why the auto-train did not seem to work properly.
v3: Paulo Zanoni pointed out that this workaround is also required on
the LPT PCH. And Arthur Ranyan confirmed that this workaround is
requierd for all ports on the pch, not just DP: The important part
is that the bit is set whenever the pch transcoder is enabled, and
that it is _not_ set while the fdi link is trained. It is also
important that the pch transcoder is fully disabled, i.e. we have to
wait for bit 30 to clear before clearing the w/a bit.
Hence move to workaround into enable/disable_transcoder, where the pch
transcoder gets enabled/disabled.
v4: Whitespace changes dropped.
v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT.
v6:
- resolve conflicts with Paulo's big hsw vga rework
- s/!IBX/CPT since hsw paths are now all separate, and Paulo's patch
to implement the equivalent w/a for LPT is already merged.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Arthur Ranyan <arthur.j.runyan@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v5)
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v5)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-11-01 09:15:30 +01:00
|
|
|
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
|
2015-09-18 20:03:31 +03:00
|
|
|
I915_WRITE(TRANS_CHICKEN2(PIPE_A), val);
|
2012-10-31 18:12:52 -02:00
|
|
|
|
2012-10-31 18:12:49 -02:00
|
|
|
val = TRANS_ENABLE;
|
2012-10-31 18:12:47 -02:00
|
|
|
pipeconf_val = I915_READ(PIPECONF(cpu_transcoder));
|
2012-10-31 18:12:43 -02:00
|
|
|
|
2012-10-31 18:12:48 -02:00
|
|
|
if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) ==
|
|
|
|
|
PIPECONF_INTERLACED_ILK)
|
2012-10-31 18:12:45 -02:00
|
|
|
val |= TRANS_INTERLACED;
|
2012-10-31 18:12:43 -02:00
|
|
|
else
|
|
|
|
|
val |= TRANS_PROGRESSIVE;
|
|
|
|
|
|
2013-05-03 11:49:46 +02:00
|
|
|
I915_WRITE(LPT_TRANSCONF, val);
|
2016-06-30 15:32:58 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
LPT_TRANSCONF,
|
|
|
|
|
TRANS_STATE_ENABLE,
|
|
|
|
|
TRANS_STATE_ENABLE,
|
|
|
|
|
100))
|
2012-10-31 18:12:47 -02:00
|
|
|
DRM_ERROR("Failed to enable PCH transcoder\n");
|
2012-10-31 18:12:43 -02:00
|
|
|
}
|
|
|
|
|
|
2012-10-31 18:12:42 -02:00
|
|
|
static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
2011-01-03 12:14:26 -08:00
|
|
|
{
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
uint32_t val;
|
2011-01-03 12:14:26 -08:00
|
|
|
|
|
|
|
|
/* FDI relies on the transcoder */
|
|
|
|
|
assert_fdi_tx_disabled(dev_priv, pipe);
|
|
|
|
|
assert_fdi_rx_disabled(dev_priv, pipe);
|
|
|
|
|
|
2011-02-02 12:28:03 -08:00
|
|
|
/* Ports must be off as well */
|
|
|
|
|
assert_pch_ports_disabled(dev_priv, pipe);
|
|
|
|
|
|
2013-05-03 11:49:46 +02:00
|
|
|
reg = PCH_TRANSCONF(pipe);
|
2011-01-03 12:14:26 -08:00
|
|
|
val = I915_READ(reg);
|
|
|
|
|
val &= ~TRANS_ENABLE;
|
|
|
|
|
I915_WRITE(reg, val);
|
|
|
|
|
/* wait for PCH transcoder off, transcoder state */
|
2016-06-30 15:32:59 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
reg, TRANS_STATE_ENABLE, 0,
|
|
|
|
|
50))
|
2013-04-17 17:48:50 +03:00
|
|
|
DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe));
|
drm/i915: CPT+ pch transcoder workaround
We need to set the timing override chicken bit after fdi link training
has completed and before we enable the transcoder. We also have to
clear that bit again after disabling the pch transcoder.
See "Graphics BSpec: vol4g North Display Engine Registers [IVB],
Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display
Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI
Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31:
"Workaround : Enable the override prior to enabling the transcoder.
Disable the override after disabling the transcoder."
While at it, use the _PIPE macro for the other TRANS_DP register.
v2: Keep the w/a as-is, but kill the original (but wrongly placed)
workaround introduced in
commit 3bcf603f6d5d18bd9d076dc280de71f48add4101
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Wed Jul 27 11:51:40 2011 -0700
drm/i915: apply timing generator bug workaround on CPT and PPT
and
commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Tue Oct 11 10:43:02 2011 -0700
drm/i915: export a CPT mode set verification function
Note that this old code has unconditionally set the w/a, which might
explain why fdi link training sometimes silently fails, and especially
why the auto-train did not seem to work properly.
v3: Paulo Zanoni pointed out that this workaround is also required on
the LPT PCH. And Arthur Ranyan confirmed that this workaround is
requierd for all ports on the pch, not just DP: The important part
is that the bit is set whenever the pch transcoder is enabled, and
that it is _not_ set while the fdi link is trained. It is also
important that the pch transcoder is fully disabled, i.e. we have to
wait for bit 30 to clear before clearing the w/a bit.
Hence move to workaround into enable/disable_transcoder, where the pch
transcoder gets enabled/disabled.
v4: Whitespace changes dropped.
v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT.
v6:
- resolve conflicts with Paulo's big hsw vga rework
- s/!IBX/CPT since hsw paths are now all separate, and Paulo's patch
to implement the equivalent w/a for LPT is already merged.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Arthur Ranyan <arthur.j.runyan@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v5)
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v5)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-11-01 09:15:30 +01:00
|
|
|
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
drm/i915: CPT+ pch transcoder workaround
We need to set the timing override chicken bit after fdi link training
has completed and before we enable the transcoder. We also have to
clear that bit again after disabling the pch transcoder.
See "Graphics BSpec: vol4g North Display Engine Registers [IVB],
Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display
Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI
Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31:
"Workaround : Enable the override prior to enabling the transcoder.
Disable the override after disabling the transcoder."
While at it, use the _PIPE macro for the other TRANS_DP register.
v2: Keep the w/a as-is, but kill the original (but wrongly placed)
workaround introduced in
commit 3bcf603f6d5d18bd9d076dc280de71f48add4101
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Wed Jul 27 11:51:40 2011 -0700
drm/i915: apply timing generator bug workaround on CPT and PPT
and
commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Tue Oct 11 10:43:02 2011 -0700
drm/i915: export a CPT mode set verification function
Note that this old code has unconditionally set the w/a, which might
explain why fdi link training sometimes silently fails, and especially
why the auto-train did not seem to work properly.
v3: Paulo Zanoni pointed out that this workaround is also required on
the LPT PCH. And Arthur Ranyan confirmed that this workaround is
requierd for all ports on the pch, not just DP: The important part
is that the bit is set whenever the pch transcoder is enabled, and
that it is _not_ set while the fdi link is trained. It is also
important that the pch transcoder is fully disabled, i.e. we have to
wait for bit 30 to clear before clearing the w/a bit.
Hence move to workaround into enable/disable_transcoder, where the pch
transcoder gets enabled/disabled.
v4: Whitespace changes dropped.
v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT.
v6:
- resolve conflicts with Paulo's big hsw vga rework
- s/!IBX/CPT since hsw paths are now all separate, and Paulo's patch
to implement the equivalent w/a for LPT is already merged.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Arthur Ranyan <arthur.j.runyan@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v5)
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v5)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-11-01 09:15:30 +01:00
|
|
|
/* Workaround: Clear the timing override chicken bit again. */
|
|
|
|
|
reg = TRANS_CHICKEN2(pipe);
|
|
|
|
|
val = I915_READ(reg);
|
|
|
|
|
val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE;
|
|
|
|
|
I915_WRITE(reg, val);
|
|
|
|
|
}
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
|
2016-08-23 16:18:08 +02:00
|
|
|
void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
|
2012-10-31 18:12:43 -02:00
|
|
|
{
|
|
|
|
|
u32 val;
|
|
|
|
|
|
2013-05-03 11:49:46 +02:00
|
|
|
val = I915_READ(LPT_TRANSCONF);
|
2012-10-31 18:12:43 -02:00
|
|
|
val &= ~TRANS_ENABLE;
|
2013-05-03 11:49:46 +02:00
|
|
|
I915_WRITE(LPT_TRANSCONF, val);
|
2012-10-31 18:12:43 -02:00
|
|
|
/* wait for PCH transcoder off, transcoder state */
|
2016-06-30 15:33:00 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
LPT_TRANSCONF, TRANS_STATE_ENABLE, 0,
|
|
|
|
|
50))
|
2012-10-31 18:12:51 -02:00
|
|
|
DRM_ERROR("Failed to disable PCH transcoder\n");
|
2012-10-31 18:12:52 -02:00
|
|
|
|
|
|
|
|
/* Workaround: clear timing override bit. */
|
2015-09-18 20:03:31 +03:00
|
|
|
val = I915_READ(TRANS_CHICKEN2(PIPE_A));
|
drm/i915: CPT+ pch transcoder workaround
We need to set the timing override chicken bit after fdi link training
has completed and before we enable the transcoder. We also have to
clear that bit again after disabling the pch transcoder.
See "Graphics BSpec: vol4g North Display Engine Registers [IVB],
Display Mode Set Sequence" and "Graphics BSpec: vol4h South Display
Engine Registers [CPT, PPT], South Display Engine Transcoder and FDI
Control, Transcoder Debug and DFT, TRANS_CHICKEN_2" bit 31:
"Workaround : Enable the override prior to enabling the transcoder.
Disable the override after disabling the transcoder."
While at it, use the _PIPE macro for the other TRANS_DP register.
v2: Keep the w/a as-is, but kill the original (but wrongly placed)
workaround introduced in
commit 3bcf603f6d5d18bd9d076dc280de71f48add4101
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Wed Jul 27 11:51:40 2011 -0700
drm/i915: apply timing generator bug workaround on CPT and PPT
and
commit d4270e57efe9e2536798c59e1ed2fd0a1e5cdfcf
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date: Tue Oct 11 10:43:02 2011 -0700
drm/i915: export a CPT mode set verification function
Note that this old code has unconditionally set the w/a, which might
explain why fdi link training sometimes silently fails, and especially
why the auto-train did not seem to work properly.
v3: Paulo Zanoni pointed out that this workaround is also required on
the LPT PCH. And Arthur Ranyan confirmed that this workaround is
requierd for all ports on the pch, not just DP: The important part
is that the bit is set whenever the pch transcoder is enabled, and
that it is _not_ set while the fdi link is trained. It is also
important that the pch transcoder is fully disabled, i.e. we have to
wait for bit 30 to clear before clearing the w/a bit.
Hence move to workaround into enable/disable_transcoder, where the pch
transcoder gets enabled/disabled.
v4: Whitespace changes dropped.
v5: Don't run the w/a on IBX, we only need it on CPT/PPT and LPT.
v6:
- resolve conflicts with Paulo's big hsw vga rework
- s/!IBX/CPT since hsw paths are now all separate, and Paulo's patch
to implement the equivalent w/a for LPT is already merged.
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Arthur Ranyan <arthur.j.runyan@intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v5)
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v5)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-11-01 09:15:30 +01:00
|
|
|
val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE;
|
2015-09-18 20:03:31 +03:00
|
|
|
I915_WRITE(TRANS_CHICKEN2(PIPE_A), val);
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
|
2017-07-17 11:14:03 -07:00
|
|
|
enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
|
2016-10-14 20:02:53 +03:00
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
|
|
|
|
|
if (HAS_PCH_LPT(dev_priv))
|
2017-07-17 11:14:03 -07:00
|
|
|
return PIPE_A;
|
2016-10-14 20:02:53 +03:00
|
|
|
else
|
2017-07-17 11:14:03 -07:00
|
|
|
return crtc->pipe;
|
2016-10-14 20:02:53 +03:00
|
|
|
}
|
|
|
|
|
|
2017-11-29 17:37:32 +02:00
|
|
|
static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
|
2011-01-04 15:09:30 -08:00
|
|
|
{
|
2017-11-29 17:37:32 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder;
|
2014-01-17 13:51:09 -02:00
|
|
|
enum pipe pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
2011-01-04 15:09:30 -08:00
|
|
|
u32 val;
|
|
|
|
|
|
2015-06-24 21:59:35 +03:00
|
|
|
DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe));
|
|
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
assert_planes_disabled(crtc);
|
2013-04-11 16:29:09 +02:00
|
|
|
|
2011-01-04 15:09:30 -08:00
|
|
|
/*
|
|
|
|
|
* A pipe without a PLL won't actually be able to drive bits from
|
|
|
|
|
* a plane. On ILK+ the pipe PLLs are integrated, so we don't
|
|
|
|
|
* need the check.
|
|
|
|
|
*/
|
2016-08-05 20:41:34 +03:00
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv)) {
|
2017-11-29 17:37:32 +02:00
|
|
|
if (intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI))
|
2013-08-27 15:12:22 +03:00
|
|
|
assert_dsi_pll_enabled(dev_priv);
|
|
|
|
|
else
|
|
|
|
|
assert_pll_enabled(dev_priv, pipe);
|
2016-08-05 20:41:34 +03:00
|
|
|
} else {
|
2017-11-29 17:37:32 +02:00
|
|
|
if (new_crtc_state->has_pch_encoder) {
|
2011-01-03 12:14:26 -08:00
|
|
|
/* if driving the PCH, we need FDI enabled */
|
2016-10-14 20:02:53 +03:00
|
|
|
assert_fdi_rx_pll_enabled(dev_priv,
|
2017-07-17 11:14:03 -07:00
|
|
|
intel_crtc_pch_transcoder(crtc));
|
2012-11-29 22:18:51 +01:00
|
|
|
assert_fdi_tx_pll_enabled(dev_priv,
|
|
|
|
|
(enum pipe) cpu_transcoder);
|
2011-01-03 12:14:26 -08:00
|
|
|
}
|
|
|
|
|
/* FIXME: assert CPU port conditions for SNB+ */
|
|
|
|
|
}
|
2011-01-04 15:09:30 -08:00
|
|
|
|
2012-10-23 18:29:59 -02:00
|
|
|
reg = PIPECONF(cpu_transcoder);
|
2011-01-04 15:09:30 -08:00
|
|
|
val = I915_READ(reg);
|
2014-01-17 13:51:13 -02:00
|
|
|
if (val & PIPECONF_ENABLE) {
|
2017-06-01 17:36:19 +03:00
|
|
|
/* we keep both pipes enabled on 830 */
|
|
|
|
|
WARN_ON(!IS_I830(dev_priv));
|
2011-03-17 07:18:29 +00:00
|
|
|
return;
|
2014-01-17 13:51:13 -02:00
|
|
|
}
|
2011-03-17 07:18:29 +00:00
|
|
|
|
|
|
|
|
I915_WRITE(reg, val | PIPECONF_ENABLE);
|
2013-12-19 19:12:29 -02:00
|
|
|
POSTING_READ(reg);
|
2015-12-14 18:23:43 +02:00
|
|
|
|
|
|
|
|
/*
|
2017-11-29 17:37:30 +02:00
|
|
|
* Until the pipe starts PIPEDSL reads will return a stale value,
|
|
|
|
|
* which causes an apparent vblank timestamp jump when PIPEDSL
|
|
|
|
|
* resets to its proper value. That also messes up the frame count
|
|
|
|
|
* when it's derived from the timestamps. So let's wait for the
|
|
|
|
|
* pipe to start properly before we call drm_crtc_vblank_on()
|
2015-12-14 18:23:43 +02:00
|
|
|
*/
|
2017-11-29 17:37:32 +02:00
|
|
|
if (dev_priv->drm.max_vblank_count == 0)
|
2017-11-29 17:37:30 +02:00
|
|
|
intel_wait_for_pipe_scanline_moving(crtc);
|
2011-01-04 15:09:30 -08:00
|
|
|
}
|
|
|
|
|
|
2017-11-29 17:37:32 +02:00
|
|
|
static void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state)
|
2011-01-04 15:09:30 -08:00
|
|
|
{
|
2017-11-29 17:37:32 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2017-11-29 17:37:32 +02:00
|
|
|
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
|
2014-08-15 01:21:56 +03:00
|
|
|
enum pipe pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
2011-01-04 15:09:30 -08:00
|
|
|
u32 val;
|
|
|
|
|
|
2015-06-24 21:59:35 +03:00
|
|
|
DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe));
|
|
|
|
|
|
2011-01-04 15:09:30 -08:00
|
|
|
/*
|
|
|
|
|
* Make sure planes won't keep trying to pump pixels to us,
|
|
|
|
|
* or we might hang the display.
|
|
|
|
|
*/
|
2017-11-17 21:19:08 +02:00
|
|
|
assert_planes_disabled(crtc);
|
2011-01-04 15:09:30 -08:00
|
|
|
|
2012-10-23 18:29:59 -02:00
|
|
|
reg = PIPECONF(cpu_transcoder);
|
2011-01-04 15:09:30 -08:00
|
|
|
val = I915_READ(reg);
|
2011-03-17 07:18:29 +00:00
|
|
|
if ((val & PIPECONF_ENABLE) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2014-08-15 01:21:57 +03:00
|
|
|
/*
|
|
|
|
|
* Double wide has implications for planes
|
|
|
|
|
* so best keep it disabled when not needed.
|
|
|
|
|
*/
|
2017-11-29 17:37:32 +02:00
|
|
|
if (old_crtc_state->double_wide)
|
2014-08-15 01:21:57 +03:00
|
|
|
val &= ~PIPECONF_DOUBLE_WIDE;
|
|
|
|
|
|
|
|
|
|
/* Don't disable pipe or pipe PLLs if needed */
|
2017-06-01 17:36:19 +03:00
|
|
|
if (!IS_I830(dev_priv))
|
2014-08-15 01:21:57 +03:00
|
|
|
val &= ~PIPECONF_ENABLE;
|
|
|
|
|
|
|
|
|
|
I915_WRITE(reg, val);
|
|
|
|
|
if ((val & PIPECONF_ENABLE) == 0)
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_wait_for_pipe_off(old_crtc_state);
|
2011-01-04 15:09:30 -08:00
|
|
|
}
|
|
|
|
|
|
2016-01-12 21:08:33 +02:00
|
|
|
static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
return IS_GEN2(dev_priv) ? 2048 : 4096;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
static unsigned int
|
|
|
|
|
intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane)
|
2016-01-12 21:08:32 +02:00
|
|
|
{
|
2017-03-07 21:42:06 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(fb->dev);
|
|
|
|
|
unsigned int cpp = fb->format->cpp[plane];
|
|
|
|
|
|
|
|
|
|
switch (fb->modifier) {
|
2017-03-24 14:29:48 -07:00
|
|
|
case DRM_FORMAT_MOD_LINEAR:
|
2016-01-12 21:08:32 +02:00
|
|
|
return cpp;
|
|
|
|
|
case I915_FORMAT_MOD_X_TILED:
|
|
|
|
|
if (IS_GEN2(dev_priv))
|
|
|
|
|
return 128;
|
|
|
|
|
else
|
|
|
|
|
return 512;
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
|
|
|
|
if (plane == 1)
|
|
|
|
|
return 128;
|
|
|
|
|
/* fall through */
|
2016-01-12 21:08:32 +02:00
|
|
|
case I915_FORMAT_MOD_Y_TILED:
|
|
|
|
|
if (IS_GEN2(dev_priv) || HAS_128_BYTE_Y_TILING(dev_priv))
|
|
|
|
|
return 128;
|
|
|
|
|
else
|
|
|
|
|
return 512;
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Yf_TILED_CCS:
|
|
|
|
|
if (plane == 1)
|
|
|
|
|
return 128;
|
|
|
|
|
/* fall through */
|
2016-01-12 21:08:32 +02:00
|
|
|
case I915_FORMAT_MOD_Yf_TILED:
|
|
|
|
|
switch (cpp) {
|
|
|
|
|
case 1:
|
|
|
|
|
return 64;
|
|
|
|
|
case 2:
|
|
|
|
|
case 4:
|
|
|
|
|
return 128;
|
|
|
|
|
case 8:
|
|
|
|
|
case 16:
|
|
|
|
|
return 256;
|
|
|
|
|
default:
|
|
|
|
|
MISSING_CASE(cpp);
|
|
|
|
|
return cpp;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2017-03-07 21:42:06 +02:00
|
|
|
MISSING_CASE(fb->modifier);
|
2016-01-12 21:08:32 +02:00
|
|
|
return cpp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
static unsigned int
|
|
|
|
|
intel_tile_height(const struct drm_framebuffer *fb, int plane)
|
2014-02-07 12:10:35 -08:00
|
|
|
{
|
2017-03-24 14:29:48 -07:00
|
|
|
if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
|
2016-01-12 21:08:33 +02:00
|
|
|
return 1;
|
|
|
|
|
else
|
2017-03-07 21:42:06 +02:00
|
|
|
return intel_tile_size(to_i915(fb->dev)) /
|
|
|
|
|
intel_tile_width_bytes(fb, plane);
|
2015-03-23 11:10:32 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-15 22:54:41 +02:00
|
|
|
/* Return the tile dimensions in pixel units */
|
2017-03-07 21:42:06 +02:00
|
|
|
static void intel_tile_dims(const struct drm_framebuffer *fb, int plane,
|
2016-02-15 22:54:41 +02:00
|
|
|
unsigned int *tile_width,
|
2017-03-07 21:42:06 +02:00
|
|
|
unsigned int *tile_height)
|
2016-02-15 22:54:41 +02:00
|
|
|
{
|
2017-03-07 21:42:06 +02:00
|
|
|
unsigned int tile_width_bytes = intel_tile_width_bytes(fb, plane);
|
|
|
|
|
unsigned int cpp = fb->format->cpp[plane];
|
2016-02-15 22:54:41 +02:00
|
|
|
|
|
|
|
|
*tile_width = tile_width_bytes / cpp;
|
2017-03-07 21:42:06 +02:00
|
|
|
*tile_height = intel_tile_size(to_i915(fb->dev)) / tile_width_bytes;
|
2016-02-15 22:54:41 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-23 11:10:32 +00:00
|
|
|
unsigned int
|
2017-03-07 21:42:06 +02:00
|
|
|
intel_fb_align_height(const struct drm_framebuffer *fb,
|
|
|
|
|
int plane, unsigned int height)
|
2015-03-23 11:10:32 +00:00
|
|
|
{
|
2017-03-07 21:42:06 +02:00
|
|
|
unsigned int tile_height = intel_tile_height(fb, plane);
|
2016-01-12 21:08:33 +02:00
|
|
|
|
|
|
|
|
return ALIGN(height, tile_height);
|
2014-02-07 12:10:35 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-15 22:54:45 +02:00
|
|
|
unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info)
|
|
|
|
|
{
|
|
|
|
|
unsigned int size = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++)
|
|
|
|
|
size += rot_info->plane[i].width * rot_info->plane[i].height;
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-14 16:51:04 +02:00
|
|
|
static void
|
2016-02-15 22:54:43 +02:00
|
|
|
intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
|
|
|
|
|
const struct drm_framebuffer *fb,
|
|
|
|
|
unsigned int rotation)
|
2015-03-23 11:10:35 +00:00
|
|
|
{
|
2017-01-14 00:28:26 +00:00
|
|
|
view->type = I915_GGTT_VIEW_NORMAL;
|
2016-09-26 19:30:46 +03:00
|
|
|
if (drm_rotation_90_or_270(rotation)) {
|
2017-01-14 00:28:26 +00:00
|
|
|
view->type = I915_GGTT_VIEW_ROTATED;
|
2017-01-14 00:28:25 +00:00
|
|
|
view->rotated = to_intel_framebuffer(fb)->rot_info;
|
2016-02-15 22:54:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-03-23 11:10:36 +00:00
|
|
|
|
2017-03-27 21:55:43 +03:00
|
|
|
static unsigned int intel_cursor_alignment(const struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
if (IS_I830(dev_priv))
|
|
|
|
|
return 16 * 1024;
|
|
|
|
|
else if (IS_I85X(dev_priv))
|
|
|
|
|
return 256;
|
2017-03-27 21:55:45 +03:00
|
|
|
else if (IS_I845G(dev_priv) || IS_I865G(dev_priv))
|
|
|
|
|
return 32;
|
2017-03-27 21:55:43 +03:00
|
|
|
else
|
|
|
|
|
return 4 * 1024;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-12 21:08:37 +02:00
|
|
|
static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
|
2015-06-11 16:31:14 +03:00
|
|
|
{
|
2018-02-09 21:58:46 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2015-06-11 16:31:14 +03:00
|
|
|
return 256 * 1024;
|
2016-12-07 12:13:04 +02:00
|
|
|
else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
|
2015-12-09 12:29:35 -08:00
|
|
|
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
2015-06-11 16:31:14 +03:00
|
|
|
return 128 * 1024;
|
2018-02-09 21:58:46 +00:00
|
|
|
else if (INTEL_GEN(dev_priv) >= 4)
|
2015-06-11 16:31:14 +03:00
|
|
|
return 4 * 1024;
|
|
|
|
|
else
|
2015-06-11 16:31:16 +03:00
|
|
|
return 0;
|
2015-06-11 16:31:14 +03:00
|
|
|
}
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
|
|
|
|
|
int plane)
|
2016-01-12 21:08:37 +02:00
|
|
|
{
|
2017-03-07 21:42:06 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(fb->dev);
|
|
|
|
|
|
2017-03-07 21:42:07 +02:00
|
|
|
/* AUX_DIST needs only 4K alignment */
|
2017-08-01 09:58:13 -07:00
|
|
|
if (plane == 1)
|
2017-03-07 21:42:07 +02:00
|
|
|
return 4096;
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
switch (fb->modifier) {
|
2017-03-24 14:29:48 -07:00
|
|
|
case DRM_FORMAT_MOD_LINEAR:
|
2016-01-12 21:08:37 +02:00
|
|
|
return intel_linear_alignment(dev_priv);
|
|
|
|
|
case I915_FORMAT_MOD_X_TILED:
|
2017-03-07 21:42:06 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2016-01-12 21:08:37 +02:00
|
|
|
return 256 * 1024;
|
|
|
|
|
return 0;
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED_CCS:
|
2016-01-12 21:08:37 +02:00
|
|
|
case I915_FORMAT_MOD_Y_TILED:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED:
|
|
|
|
|
return 1 * 1024 * 1024;
|
|
|
|
|
default:
|
2017-03-07 21:42:06 +02:00
|
|
|
MISSING_CASE(fb->modifier);
|
2016-01-12 21:08:37 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 10:49:06 +01:00
|
|
|
struct i915_vma *
|
|
|
|
|
intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
|
2009-11-18 11:25:18 -05:00
|
|
|
{
|
2014-10-30 16:39:38 +00:00
|
|
|
struct drm_device *dev = fb->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-10-30 16:39:38 +00:00
|
|
|
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
2015-03-23 11:10:35 +00:00
|
|
|
struct i915_ggtt_view view;
|
2016-08-15 10:49:06 +01:00
|
|
|
struct i915_vma *vma;
|
2009-11-18 11:25:18 -05:00
|
|
|
u32 alignment;
|
|
|
|
|
|
2014-07-09 16:22:11 -07:00
|
|
|
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
alignment = intel_surf_alignment(fb, 0);
|
2009-11-18 11:25:18 -05:00
|
|
|
|
2016-02-15 22:54:43 +02:00
|
|
|
intel_fill_fb_ggtt_view(&view, fb, rotation);
|
2015-03-23 11:10:35 +00:00
|
|
|
|
2013-03-05 14:52:39 +00:00
|
|
|
/* Note that the w/a also requires 64 PTE of padding following the
|
|
|
|
|
* bo. We currently fill all unused PTE with the shadow page and so
|
|
|
|
|
* we should always have valid PTE following the scanout preventing
|
|
|
|
|
* the VT-d warning.
|
|
|
|
|
*/
|
2016-06-24 14:07:14 +01:00
|
|
|
if (intel_scanout_needs_vtd_wa(dev_priv) && alignment < 256 * 1024)
|
2013-03-05 14:52:39 +00:00
|
|
|
alignment = 256 * 1024;
|
|
|
|
|
|
2014-08-15 15:59:32 -03:00
|
|
|
/*
|
|
|
|
|
* Global gtt pte registers are special registers which actually forward
|
|
|
|
|
* writes to a chunk of system memory. Which means that there is no risk
|
|
|
|
|
* that the register values disappear as soon as we call
|
|
|
|
|
* intel_runtime_pm_put(), so it is correct to wrap only the
|
|
|
|
|
* pin/unpin/fence and not more.
|
|
|
|
|
*/
|
|
|
|
|
intel_runtime_pm_get(dev_priv);
|
|
|
|
|
|
drm/i915: More surgically unbreak the modeset vs reset deadlock
There's no reason to entirely wedge the gpu, for the minimal deadlock
bugfix we only need to unbreak/decouple the atomic commit from the gpu
reset. The simplest way to fix that is by replacing the
unconditional fence wait a the top of commit_tail by a wait which
completes either when the fences are done (normal case, or when a
reset doesn't need to touch the display state). Or when the gpu reset
needs to force-unblock all pending modeset states.
The lesser source of deadlocks is when we try to pin a new framebuffer
and run into a stall. There's a bunch of places this can happen, like
eviction, changing the caching mode, acquiring a fence on older
platforms. And we can't just break the depency loop and keep going,
the only way would be to break out and restart. But the problem with
that approach is that we must stall for the reset to complete before
we grab any locks, and with the atomic infrastructure that's a bit
tricky. The only place is the ioctl code, and we don't want to insert
code into e.g. the BUSY ioctl. Hence for that problem just create a
critical section, and if any code is in there, wedge the GPU. For the
steady-state this should never be a problem.
Note that in both cases TDR itself keeps working, so from a userspace
pov this trickery isn't observable. Users themselvs might spot a short
glitch while the rendering is catching up again, but that's still
better than pre-TDR where we've thrown away all the rendering,
including innocent batches. Also, this fixes the regression TDR
introduced of making gpu resets deadlock-prone when we do need to
touch the display.
One thing I noticed is that gpu_error.flags seems to use both our own
wait-queue in gpu_error.wait_queue, and the generic wait_on_bit
facilities. Not entirely sure why this inconsistency exists, I just
picked one style.
A possible future avenue could be to insert the gpu reset in-between
ongoing modeset changes, which would avoid the momentary glitch. But
that's a lot more work to implement in the atomic commit machinery,
and given that we only need this for pre-g4x hw, of questionable
utility just for the sake of polishing gpu reset even more on those
old boxes. It might be useful for other features though.
v2: Rebase onto 4.13 with a s/wait_queue_t/struct wait_queue_entry/.
v3: Really emabarrassing fixup, I checked the wrong bit and broke the
unbreak/wakeup logic.
v4: Also handle deadlocks in pin_to_display.
v5: Review from Michel:
- Fixup the BUILD_BUG_ON
- Don't forget about the overlay
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v2)
Cc: Michel Thierry <michel.thierry@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170808080828.23650-3-daniel.vetter@ffwll.ch
Reviewed-by: Michel Thierry <michel.thierry@intel.com>
2017-08-08 10:08:28 +02:00
|
|
|
atomic_inc(&dev_priv->gpu_error.pending_fb_pin);
|
|
|
|
|
|
2016-08-15 10:49:06 +01:00
|
|
|
vma = i915_gem_object_pin_to_display_plane(obj, alignment, &view);
|
2016-08-18 17:17:00 +01:00
|
|
|
if (IS_ERR(vma))
|
|
|
|
|
goto err;
|
2009-11-18 11:25:18 -05:00
|
|
|
|
2016-08-18 17:16:55 +01:00
|
|
|
if (i915_vma_is_map_and_fenceable(vma)) {
|
2016-08-18 17:17:00 +01:00
|
|
|
/* Install a fence for tiled scan-out. Pre-i965 always needs a
|
|
|
|
|
* fence, whereas 965+ only requires a fence if using
|
|
|
|
|
* framebuffer compression. For simplicity, we always, when
|
|
|
|
|
* possible, install a fence as the cost is not that onerous.
|
|
|
|
|
*
|
|
|
|
|
* If we fail to fence the tiled scanout, then either the
|
|
|
|
|
* modeset will reject the change (which is highly unlikely as
|
|
|
|
|
* the affected systems, all but one, do not have unmappable
|
|
|
|
|
* space) or we will not be able to enable full powersaving
|
|
|
|
|
* techniques (also likely not to apply due to various limits
|
|
|
|
|
* FBC and the like impose on the size of the buffer, which
|
|
|
|
|
* presumably we violated anyway with this unmappable buffer).
|
|
|
|
|
* Anyway, it is presumably better to stumble onwards with
|
|
|
|
|
* something and try to run the system in a "less than optimal"
|
|
|
|
|
* mode that matches the user configuration.
|
|
|
|
|
*/
|
2017-10-09 09:43:56 +01:00
|
|
|
i915_vma_pin_fence(vma);
|
2015-10-29 18:54:38 -07:00
|
|
|
}
|
2009-11-18 11:25:18 -05:00
|
|
|
|
2017-01-16 15:21:27 +00:00
|
|
|
i915_vma_get(vma);
|
2016-08-18 17:17:00 +01:00
|
|
|
err:
|
drm/i915: More surgically unbreak the modeset vs reset deadlock
There's no reason to entirely wedge the gpu, for the minimal deadlock
bugfix we only need to unbreak/decouple the atomic commit from the gpu
reset. The simplest way to fix that is by replacing the
unconditional fence wait a the top of commit_tail by a wait which
completes either when the fences are done (normal case, or when a
reset doesn't need to touch the display state). Or when the gpu reset
needs to force-unblock all pending modeset states.
The lesser source of deadlocks is when we try to pin a new framebuffer
and run into a stall. There's a bunch of places this can happen, like
eviction, changing the caching mode, acquiring a fence on older
platforms. And we can't just break the depency loop and keep going,
the only way would be to break out and restart. But the problem with
that approach is that we must stall for the reset to complete before
we grab any locks, and with the atomic infrastructure that's a bit
tricky. The only place is the ioctl code, and we don't want to insert
code into e.g. the BUSY ioctl. Hence for that problem just create a
critical section, and if any code is in there, wedge the GPU. For the
steady-state this should never be a problem.
Note that in both cases TDR itself keeps working, so from a userspace
pov this trickery isn't observable. Users themselvs might spot a short
glitch while the rendering is catching up again, but that's still
better than pre-TDR where we've thrown away all the rendering,
including innocent batches. Also, this fixes the regression TDR
introduced of making gpu resets deadlock-prone when we do need to
touch the display.
One thing I noticed is that gpu_error.flags seems to use both our own
wait-queue in gpu_error.wait_queue, and the generic wait_on_bit
facilities. Not entirely sure why this inconsistency exists, I just
picked one style.
A possible future avenue could be to insert the gpu reset in-between
ongoing modeset changes, which would avoid the momentary glitch. But
that's a lot more work to implement in the atomic commit machinery,
and given that we only need this for pre-g4x hw, of questionable
utility just for the sake of polishing gpu reset even more on those
old boxes. It might be useful for other features though.
v2: Rebase onto 4.13 with a s/wait_queue_t/struct wait_queue_entry/.
v3: Really emabarrassing fixup, I checked the wrong bit and broke the
unbreak/wakeup logic.
v4: Also handle deadlocks in pin_to_display.
v5: Review from Michel:
- Fixup the BUILD_BUG_ON
- Don't forget about the overlay
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v2)
Cc: Michel Thierry <michel.thierry@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170808080828.23650-3-daniel.vetter@ffwll.ch
Reviewed-by: Michel Thierry <michel.thierry@intel.com>
2017-08-08 10:08:28 +02:00
|
|
|
atomic_dec(&dev_priv->gpu_error.pending_fb_pin);
|
|
|
|
|
|
2014-08-15 15:59:32 -03:00
|
|
|
intel_runtime_pm_put(dev_priv);
|
2016-08-15 10:49:06 +01:00
|
|
|
return vma;
|
2009-11-18 11:25:18 -05:00
|
|
|
}
|
|
|
|
|
|
2017-01-16 15:21:27 +00:00
|
|
|
void intel_unpin_fb_vma(struct i915_vma *vma)
|
2011-12-14 13:57:08 +01:00
|
|
|
{
|
2017-01-16 15:21:27 +00:00
|
|
|
lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
|
2015-03-23 11:10:35 +00:00
|
|
|
|
2016-08-18 17:17:00 +01:00
|
|
|
i915_vma_unpin_fence(vma);
|
2016-08-15 10:49:06 +01:00
|
|
|
i915_gem_object_unpin_from_display_plane(vma);
|
2017-01-16 15:21:27 +00:00
|
|
|
i915_vma_put(vma);
|
2011-12-14 13:57:08 +01:00
|
|
|
}
|
|
|
|
|
|
2015-10-13 22:48:39 +03:00
|
|
|
static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
|
|
|
|
|
unsigned int rotation)
|
|
|
|
|
{
|
2016-09-26 19:30:46 +03:00
|
|
|
if (drm_rotation_90_or_270(rotation))
|
2015-10-13 22:48:39 +03:00
|
|
|
return to_intel_framebuffer(fb)->rotated[plane].pitch;
|
|
|
|
|
else
|
|
|
|
|
return fb->pitches[plane];
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
/*
|
|
|
|
|
* Convert the x/y offsets into a linear offset.
|
|
|
|
|
* Only valid with 0/180 degree rotation, which is fine since linear
|
|
|
|
|
* offset is only used with linear buffers on pre-hsw and tiled buffers
|
|
|
|
|
* with gen2/3, and 90/270 degree rotations isn't supported on any of them.
|
|
|
|
|
*/
|
|
|
|
|
u32 intel_fb_xy_to_linear(int x, int y,
|
2016-01-20 18:02:50 +02:00
|
|
|
const struct intel_plane_state *state,
|
|
|
|
|
int plane)
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
{
|
2016-01-20 18:02:50 +02:00
|
|
|
const struct drm_framebuffer *fb = state->base.fb;
|
2016-12-14 23:30:57 +02:00
|
|
|
unsigned int cpp = fb->format->cpp[plane];
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
unsigned int pitch = fb->pitches[plane];
|
|
|
|
|
|
|
|
|
|
return y * pitch + x * cpp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Add the x/y offsets derived from fb->offsets[] to the user
|
|
|
|
|
* specified plane src x/y offsets. The resulting x/y offsets
|
|
|
|
|
* specify the start of scanout from the beginning of the gtt mapping.
|
|
|
|
|
*/
|
|
|
|
|
void intel_add_fb_offsets(int *x, int *y,
|
2016-01-20 18:02:50 +02:00
|
|
|
const struct intel_plane_state *state,
|
|
|
|
|
int plane)
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
|
|
|
|
{
|
2016-01-20 18:02:50 +02:00
|
|
|
const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb);
|
|
|
|
|
unsigned int rotation = state->base.rotation;
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2016-09-26 19:30:46 +03:00
|
|
|
if (drm_rotation_90_or_270(rotation)) {
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
*x += intel_fb->rotated[plane].x;
|
|
|
|
|
*y += intel_fb->rotated[plane].y;
|
|
|
|
|
} else {
|
|
|
|
|
*x += intel_fb->normal[plane].x;
|
|
|
|
|
*y += intel_fb->normal[plane].y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
static u32 __intel_adjust_tile_offset(int *x, int *y,
|
|
|
|
|
unsigned int tile_width,
|
|
|
|
|
unsigned int tile_height,
|
|
|
|
|
unsigned int tile_size,
|
|
|
|
|
unsigned int pitch_tiles,
|
|
|
|
|
u32 old_offset,
|
|
|
|
|
u32 new_offset)
|
2016-02-15 22:54:42 +02:00
|
|
|
{
|
2016-02-08 18:28:00 +02:00
|
|
|
unsigned int pitch_pixels = pitch_tiles * tile_width;
|
2016-02-15 22:54:42 +02:00
|
|
|
unsigned int tiles;
|
|
|
|
|
|
|
|
|
|
WARN_ON(old_offset & (tile_size - 1));
|
|
|
|
|
WARN_ON(new_offset & (tile_size - 1));
|
|
|
|
|
WARN_ON(new_offset > old_offset);
|
|
|
|
|
|
|
|
|
|
tiles = (old_offset - new_offset) / tile_size;
|
|
|
|
|
|
|
|
|
|
*y += tiles / pitch_tiles * tile_height;
|
|
|
|
|
*x += tiles % pitch_tiles * tile_width;
|
|
|
|
|
|
2016-02-08 18:28:00 +02:00
|
|
|
/* minimize x in case it got needlessly big */
|
|
|
|
|
*y += *x / pitch_pixels * tile_height;
|
|
|
|
|
*x %= pitch_pixels;
|
|
|
|
|
|
2016-02-15 22:54:42 +02:00
|
|
|
return new_offset;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
static u32 _intel_adjust_tile_offset(int *x, int *y,
|
|
|
|
|
const struct drm_framebuffer *fb, int plane,
|
|
|
|
|
unsigned int rotation,
|
|
|
|
|
u32 old_offset, u32 new_offset)
|
2016-02-05 18:44:05 +02:00
|
|
|
{
|
2017-08-24 22:10:49 +03:00
|
|
|
const struct drm_i915_private *dev_priv = to_i915(fb->dev);
|
2016-12-14 23:30:57 +02:00
|
|
|
unsigned int cpp = fb->format->cpp[plane];
|
2016-02-05 18:44:05 +02:00
|
|
|
unsigned int pitch = intel_fb_pitch(fb, plane, rotation);
|
|
|
|
|
|
|
|
|
|
WARN_ON(new_offset > old_offset);
|
|
|
|
|
|
2017-03-24 14:29:48 -07:00
|
|
|
if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
|
2016-02-05 18:44:05 +02:00
|
|
|
unsigned int tile_size, tile_width, tile_height;
|
|
|
|
|
unsigned int pitch_tiles;
|
|
|
|
|
|
|
|
|
|
tile_size = intel_tile_size(dev_priv);
|
2017-03-07 21:42:06 +02:00
|
|
|
intel_tile_dims(fb, plane, &tile_width, &tile_height);
|
2016-02-05 18:44:05 +02:00
|
|
|
|
2016-09-26 19:30:46 +03:00
|
|
|
if (drm_rotation_90_or_270(rotation)) {
|
2016-02-05 18:44:05 +02:00
|
|
|
pitch_tiles = pitch / tile_height;
|
|
|
|
|
swap(tile_width, tile_height);
|
|
|
|
|
} else {
|
|
|
|
|
pitch_tiles = pitch / (tile_width * cpp);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
__intel_adjust_tile_offset(x, y, tile_width, tile_height,
|
|
|
|
|
tile_size, pitch_tiles,
|
|
|
|
|
old_offset, new_offset);
|
2016-02-05 18:44:05 +02:00
|
|
|
} else {
|
|
|
|
|
old_offset += *y * pitch + *x * cpp;
|
|
|
|
|
|
|
|
|
|
*y = (old_offset - new_offset) / pitch;
|
|
|
|
|
*x = ((old_offset - new_offset) - *y * pitch) / cpp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new_offset;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
/*
|
|
|
|
|
* Adjust the tile offset by moving the difference into
|
|
|
|
|
* the x/y offsets.
|
|
|
|
|
*/
|
|
|
|
|
static u32 intel_adjust_tile_offset(int *x, int *y,
|
|
|
|
|
const struct intel_plane_state *state, int plane,
|
|
|
|
|
u32 old_offset, u32 new_offset)
|
|
|
|
|
{
|
|
|
|
|
return _intel_adjust_tile_offset(x, y, state->base.fb, plane,
|
|
|
|
|
state->base.rotation,
|
|
|
|
|
old_offset, new_offset);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-15 22:54:41 +02:00
|
|
|
/*
|
|
|
|
|
* Computes the linear offset to the base tile and adjusts
|
|
|
|
|
* x, y. bytes per pixel is assumed to be a power-of-two.
|
|
|
|
|
*
|
|
|
|
|
* In the 90/270 rotated case, x and y are assumed
|
|
|
|
|
* to be already rotated to match the rotated GTT view, and
|
|
|
|
|
* pitch is the tile_height aligned framebuffer height.
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
*
|
|
|
|
|
* This function is used when computing the derived information
|
|
|
|
|
* under intel_framebuffer, so using any of that information
|
|
|
|
|
* here is not allowed. Anything under drm_framebuffer can be
|
|
|
|
|
* used. This is why the user has to pass in the pitch since it
|
|
|
|
|
* is specified in the rotated orientation.
|
2016-02-15 22:54:41 +02:00
|
|
|
*/
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
|
|
|
|
|
int *x, int *y,
|
|
|
|
|
const struct drm_framebuffer *fb, int plane,
|
|
|
|
|
unsigned int pitch,
|
|
|
|
|
unsigned int rotation,
|
|
|
|
|
u32 alignment)
|
2012-07-05 12:17:30 +02:00
|
|
|
{
|
2016-11-16 13:33:16 +02:00
|
|
|
uint64_t fb_modifier = fb->modifier;
|
2016-12-14 23:30:57 +02:00
|
|
|
unsigned int cpp = fb->format->cpp[plane];
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
u32 offset, offset_aligned;
|
2016-02-15 22:54:42 +02:00
|
|
|
|
|
|
|
|
if (alignment)
|
|
|
|
|
alignment--;
|
|
|
|
|
|
2017-03-24 14:29:48 -07:00
|
|
|
if (fb_modifier != DRM_FORMAT_MOD_LINEAR) {
|
2016-02-15 22:54:41 +02:00
|
|
|
unsigned int tile_size, tile_width, tile_height;
|
|
|
|
|
unsigned int tile_rows, tiles, pitch_tiles;
|
2012-07-05 12:17:30 +02:00
|
|
|
|
2016-01-12 21:08:35 +02:00
|
|
|
tile_size = intel_tile_size(dev_priv);
|
2017-03-07 21:42:06 +02:00
|
|
|
intel_tile_dims(fb, plane, &tile_width, &tile_height);
|
2016-02-15 22:54:41 +02:00
|
|
|
|
2016-09-26 19:30:46 +03:00
|
|
|
if (drm_rotation_90_or_270(rotation)) {
|
2016-02-15 22:54:41 +02:00
|
|
|
pitch_tiles = pitch / tile_height;
|
|
|
|
|
swap(tile_width, tile_height);
|
|
|
|
|
} else {
|
|
|
|
|
pitch_tiles = pitch / (tile_width * cpp);
|
|
|
|
|
}
|
2016-01-12 21:08:35 +02:00
|
|
|
|
|
|
|
|
tile_rows = *y / tile_height;
|
|
|
|
|
*y %= tile_height;
|
2012-07-05 12:17:30 +02:00
|
|
|
|
2016-02-15 22:54:41 +02:00
|
|
|
tiles = *x / tile_width;
|
|
|
|
|
*x %= tile_width;
|
2013-02-21 20:04:31 +00:00
|
|
|
|
2016-02-15 22:54:42 +02:00
|
|
|
offset = (tile_rows * pitch_tiles + tiles) * tile_size;
|
|
|
|
|
offset_aligned = offset & ~alignment;
|
2013-02-21 20:04:31 +00:00
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
__intel_adjust_tile_offset(x, y, tile_width, tile_height,
|
|
|
|
|
tile_size, pitch_tiles,
|
|
|
|
|
offset, offset_aligned);
|
2016-02-15 22:54:42 +02:00
|
|
|
} else {
|
2013-02-21 20:04:31 +00:00
|
|
|
offset = *y * pitch + *x * cpp;
|
2016-02-15 22:54:42 +02:00
|
|
|
offset_aligned = offset & ~alignment;
|
|
|
|
|
|
2015-06-11 16:31:14 +03:00
|
|
|
*y = (offset & alignment) / pitch;
|
|
|
|
|
*x = ((offset & alignment) - *y * pitch) / cpp;
|
2013-02-21 20:04:31 +00:00
|
|
|
}
|
2016-02-15 22:54:42 +02:00
|
|
|
|
|
|
|
|
return offset_aligned;
|
2012-07-05 12:17:30 +02:00
|
|
|
}
|
|
|
|
|
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
u32 intel_compute_tile_offset(int *x, int *y,
|
2016-01-20 18:02:50 +02:00
|
|
|
const struct intel_plane_state *state,
|
|
|
|
|
int plane)
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
{
|
2017-03-27 21:55:44 +03:00
|
|
|
struct intel_plane *intel_plane = to_intel_plane(state->base.plane);
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
|
2016-01-20 18:02:50 +02:00
|
|
|
const struct drm_framebuffer *fb = state->base.fb;
|
|
|
|
|
unsigned int rotation = state->base.rotation;
|
2015-10-13 22:48:39 +03:00
|
|
|
int pitch = intel_fb_pitch(fb, plane, rotation);
|
2017-03-27 21:55:44 +03:00
|
|
|
u32 alignment;
|
|
|
|
|
|
|
|
|
|
if (intel_plane->id == PLANE_CURSOR)
|
|
|
|
|
alignment = intel_cursor_alignment(dev_priv);
|
|
|
|
|
else
|
|
|
|
|
alignment = intel_surf_alignment(fb, plane);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
|
|
|
|
return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
|
|
|
|
|
rotation, alignment);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
/* Convert the fb->offset[] into x/y offsets */
|
|
|
|
|
static int intel_fb_offset_to_xy(int *x, int *y,
|
|
|
|
|
const struct drm_framebuffer *fb, int plane)
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
{
|
2017-08-24 22:10:49 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(fb->dev);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
if (fb->modifier != DRM_FORMAT_MOD_LINEAR &&
|
|
|
|
|
fb->offsets[plane] % intel_tile_size(dev_priv))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
*x = 0;
|
|
|
|
|
*y = 0;
|
|
|
|
|
|
|
|
|
|
_intel_adjust_tile_offset(x, y,
|
|
|
|
|
fb, plane, DRM_MODE_ROTATE_0,
|
|
|
|
|
fb->offsets[plane], 0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
}
|
|
|
|
|
|
2016-02-04 20:38:20 +02:00
|
|
|
static unsigned int intel_fb_modifier_to_tiling(uint64_t fb_modifier)
|
|
|
|
|
{
|
|
|
|
|
switch (fb_modifier) {
|
|
|
|
|
case I915_FORMAT_MOD_X_TILED:
|
|
|
|
|
return I915_TILING_X;
|
|
|
|
|
case I915_FORMAT_MOD_Y_TILED:
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
2016-02-04 20:38:20 +02:00
|
|
|
return I915_TILING_Y;
|
|
|
|
|
default:
|
|
|
|
|
return I915_TILING_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 16:41:52 +02:00
|
|
|
/*
|
|
|
|
|
* From the Sky Lake PRM:
|
|
|
|
|
* "The Color Control Surface (CCS) contains the compression status of
|
|
|
|
|
* the cache-line pairs. The compression state of the cache-line pair
|
|
|
|
|
* is specified by 2 bits in the CCS. Each CCS cache-line represents
|
|
|
|
|
* an area on the main surface of 16 x16 sets of 128 byte Y-tiled
|
|
|
|
|
* cache-line-pairs. CCS is always Y tiled."
|
|
|
|
|
*
|
|
|
|
|
* Since cache line pairs refers to horizontally adjacent cache lines,
|
|
|
|
|
* each cache line in the CCS corresponds to an area of 32x16 cache
|
|
|
|
|
* lines on the main surface. Since each pixel is 4 bytes, this gives
|
|
|
|
|
* us a ratio of one byte in the CCS for each 8x16 pixels in the
|
|
|
|
|
* main surface.
|
|
|
|
|
*/
|
2017-08-01 09:58:12 -07:00
|
|
|
static const struct drm_format_info ccs_formats[] = {
|
|
|
|
|
{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
|
|
|
|
|
{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
|
|
|
|
|
{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
|
|
|
|
|
{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct drm_format_info *
|
|
|
|
|
lookup_format_info(const struct drm_format_info formats[],
|
|
|
|
|
int num_formats, u32 format)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_formats; i++) {
|
|
|
|
|
if (formats[i].format == format)
|
|
|
|
|
return &formats[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct drm_format_info *
|
|
|
|
|
intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
|
|
|
|
|
{
|
|
|
|
|
switch (cmd->modifier[0]) {
|
|
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED_CCS:
|
|
|
|
|
return lookup_format_info(ccs_formats,
|
|
|
|
|
ARRAY_SIZE(ccs_formats),
|
|
|
|
|
cmd->pixel_format);
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
static int
|
|
|
|
|
intel_fill_fb_info(struct drm_i915_private *dev_priv,
|
|
|
|
|
struct drm_framebuffer *fb)
|
|
|
|
|
{
|
|
|
|
|
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
|
|
|
|
|
struct intel_rotation_info *rot_info = &intel_fb->rot_info;
|
|
|
|
|
u32 gtt_offset_rotated = 0;
|
|
|
|
|
unsigned int max_size = 0;
|
2016-12-14 23:30:22 +02:00
|
|
|
int i, num_planes = fb->format->num_planes;
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
unsigned int tile_size = intel_tile_size(dev_priv);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_planes; i++) {
|
|
|
|
|
unsigned int width, height;
|
|
|
|
|
unsigned int cpp, size;
|
|
|
|
|
u32 offset;
|
|
|
|
|
int x, y;
|
2017-08-24 22:10:49 +03:00
|
|
|
int ret;
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2016-12-14 23:30:57 +02:00
|
|
|
cpp = fb->format->cpp[i];
|
2016-11-18 21:53:06 +02:00
|
|
|
width = drm_framebuffer_plane_width(fb->width, fb, i);
|
|
|
|
|
height = drm_framebuffer_plane_height(fb->height, fb, i);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
ret = intel_fb_offset_to_xy(&x, &y, fb, i);
|
|
|
|
|
if (ret) {
|
|
|
|
|
DRM_DEBUG_KMS("bad fb plane %d offset: 0x%x\n",
|
|
|
|
|
i, fb->offsets[i]);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
if ((fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
|
|
|
|
|
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) && i == 1) {
|
|
|
|
|
int hsub = fb->format->hsub;
|
|
|
|
|
int vsub = fb->format->vsub;
|
|
|
|
|
int tile_width, tile_height;
|
|
|
|
|
int main_x, main_y;
|
|
|
|
|
int ccs_x, ccs_y;
|
|
|
|
|
|
|
|
|
|
intel_tile_dims(fb, i, &tile_width, &tile_height);
|
2017-08-24 22:10:49 +03:00
|
|
|
tile_width *= hsub;
|
|
|
|
|
tile_height *= vsub;
|
2017-08-01 09:58:13 -07:00
|
|
|
|
2017-08-24 22:10:49 +03:00
|
|
|
ccs_x = (x * hsub) % tile_width;
|
|
|
|
|
ccs_y = (y * vsub) % tile_height;
|
|
|
|
|
main_x = intel_fb->normal[0].x % tile_width;
|
|
|
|
|
main_y = intel_fb->normal[0].y % tile_height;
|
2017-08-01 09:58:13 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* CCS doesn't have its own x/y offset register, so the intra CCS tile
|
|
|
|
|
* x/y offsets must match between CCS and the main surface.
|
|
|
|
|
*/
|
|
|
|
|
if (main_x != ccs_x || main_y != ccs_y) {
|
|
|
|
|
DRM_DEBUG_KMS("Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
|
|
|
|
|
main_x, main_y,
|
|
|
|
|
ccs_x, ccs_y,
|
|
|
|
|
intel_fb->normal[0].x,
|
|
|
|
|
intel_fb->normal[0].y,
|
|
|
|
|
x, y);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-22 18:41:24 +02:00
|
|
|
/*
|
|
|
|
|
* The fence (if used) is aligned to the start of the object
|
|
|
|
|
* so having the framebuffer wrap around across the edge of the
|
|
|
|
|
* fenced region doesn't really work. We have no API to configure
|
|
|
|
|
* the fence start offset within the object (nor could we probably
|
|
|
|
|
* on gen2/3). So it's just easier if we just require that the
|
|
|
|
|
* fb layout agrees with the fence layout. We already check that the
|
|
|
|
|
* fb stride matches the fence stride elsewhere.
|
|
|
|
|
*/
|
2017-08-24 22:10:50 +03:00
|
|
|
if (i == 0 && i915_gem_object_is_tiled(intel_fb->obj) &&
|
2016-01-22 18:41:24 +02:00
|
|
|
(x + width) * cpp > fb->pitches[i]) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("bad fb plane %d offset: 0x%x\n",
|
|
|
|
|
i, fb->offsets[i]);
|
2016-01-22 18:41:24 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
/*
|
|
|
|
|
* First pixel of the framebuffer from
|
|
|
|
|
* the start of the normal gtt mapping.
|
|
|
|
|
*/
|
|
|
|
|
intel_fb->normal[i].x = x;
|
|
|
|
|
intel_fb->normal[i].y = y;
|
|
|
|
|
|
|
|
|
|
offset = _intel_compute_tile_offset(dev_priv, &x, &y,
|
2017-03-07 21:42:09 +02:00
|
|
|
fb, i, fb->pitches[i],
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_0, tile_size);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
offset /= tile_size;
|
|
|
|
|
|
2017-03-24 14:29:48 -07:00
|
|
|
if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
unsigned int tile_width, tile_height;
|
|
|
|
|
unsigned int pitch_tiles;
|
|
|
|
|
struct drm_rect r;
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
intel_tile_dims(fb, i, &tile_width, &tile_height);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
|
|
|
|
rot_info->plane[i].offset = offset;
|
|
|
|
|
rot_info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width * cpp);
|
|
|
|
|
rot_info->plane[i].width = DIV_ROUND_UP(x + width, tile_width);
|
|
|
|
|
rot_info->plane[i].height = DIV_ROUND_UP(y + height, tile_height);
|
|
|
|
|
|
|
|
|
|
intel_fb->rotated[i].pitch =
|
|
|
|
|
rot_info->plane[i].height * tile_height;
|
|
|
|
|
|
|
|
|
|
/* how many tiles does this plane need */
|
|
|
|
|
size = rot_info->plane[i].stride * rot_info->plane[i].height;
|
|
|
|
|
/*
|
|
|
|
|
* If the plane isn't horizontally tile aligned,
|
|
|
|
|
* we need one more tile.
|
|
|
|
|
*/
|
|
|
|
|
if (x != 0)
|
|
|
|
|
size++;
|
|
|
|
|
|
|
|
|
|
/* rotate the x/y offsets to match the GTT view */
|
|
|
|
|
r.x1 = x;
|
|
|
|
|
r.y1 = y;
|
|
|
|
|
r.x2 = x + width;
|
|
|
|
|
r.y2 = y + height;
|
|
|
|
|
drm_rect_rotate(&r,
|
|
|
|
|
rot_info->plane[i].width * tile_width,
|
|
|
|
|
rot_info->plane[i].height * tile_height,
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_270);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
x = r.x1;
|
|
|
|
|
y = r.y1;
|
|
|
|
|
|
|
|
|
|
/* rotate the tile dimensions to match the GTT view */
|
|
|
|
|
pitch_tiles = intel_fb->rotated[i].pitch / tile_height;
|
|
|
|
|
swap(tile_width, tile_height);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We only keep the x/y offsets, so push all of the
|
|
|
|
|
* gtt offset into the x/y offsets.
|
|
|
|
|
*/
|
2017-08-24 22:10:49 +03:00
|
|
|
__intel_adjust_tile_offset(&x, &y,
|
|
|
|
|
tile_width, tile_height,
|
|
|
|
|
tile_size, pitch_tiles,
|
|
|
|
|
gtt_offset_rotated * tile_size, 0);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
|
|
|
|
gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* First pixel of the framebuffer from
|
|
|
|
|
* the start of the rotated gtt mapping.
|
|
|
|
|
*/
|
|
|
|
|
intel_fb->rotated[i].x = x;
|
|
|
|
|
intel_fb->rotated[i].y = y;
|
|
|
|
|
} else {
|
|
|
|
|
size = DIV_ROUND_UP((y + height) * fb->pitches[i] +
|
|
|
|
|
x * cpp, tile_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* how many tiles in total needed in the bo */
|
|
|
|
|
max_size = max(max_size, offset + size);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-07 21:42:10 +02:00
|
|
|
if (max_size * tile_size > intel_fb->obj->base.size) {
|
|
|
|
|
DRM_DEBUG_KMS("fb too big for bo (need %u bytes, have %zu bytes)\n",
|
|
|
|
|
max_size * tile_size, intel_fb->obj->base.size);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:50 +00:00
|
|
|
static int i9xx_format_to_fourcc(int format)
|
2014-03-07 08:57:48 -08:00
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
case DISPPLANE_8BPP:
|
|
|
|
|
return DRM_FORMAT_C8;
|
|
|
|
|
case DISPPLANE_BGRX555:
|
|
|
|
|
return DRM_FORMAT_XRGB1555;
|
|
|
|
|
case DISPPLANE_BGRX565:
|
|
|
|
|
return DRM_FORMAT_RGB565;
|
|
|
|
|
default:
|
|
|
|
|
case DISPPLANE_BGRX888:
|
|
|
|
|
return DRM_FORMAT_XRGB8888;
|
|
|
|
|
case DISPPLANE_RGBX888:
|
|
|
|
|
return DRM_FORMAT_XBGR8888;
|
|
|
|
|
case DISPPLANE_BGRX101010:
|
|
|
|
|
return DRM_FORMAT_XRGB2101010;
|
|
|
|
|
case DISPPLANE_RGBX101010:
|
|
|
|
|
return DRM_FORMAT_XBGR2101010;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:51 +00:00
|
|
|
static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
case PLANE_CTL_FORMAT_RGB_565:
|
|
|
|
|
return DRM_FORMAT_RGB565;
|
|
|
|
|
default:
|
|
|
|
|
case PLANE_CTL_FORMAT_XRGB_8888:
|
|
|
|
|
if (rgb_order) {
|
|
|
|
|
if (alpha)
|
|
|
|
|
return DRM_FORMAT_ABGR8888;
|
|
|
|
|
else
|
|
|
|
|
return DRM_FORMAT_XBGR8888;
|
|
|
|
|
} else {
|
|
|
|
|
if (alpha)
|
|
|
|
|
return DRM_FORMAT_ARGB8888;
|
|
|
|
|
else
|
|
|
|
|
return DRM_FORMAT_XRGB8888;
|
|
|
|
|
}
|
|
|
|
|
case PLANE_CTL_FORMAT_XRGB_2101010:
|
|
|
|
|
if (rgb_order)
|
|
|
|
|
return DRM_FORMAT_XBGR2101010;
|
|
|
|
|
else
|
|
|
|
|
return DRM_FORMAT_XRGB2101010;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:52 +00:00
|
|
|
static bool
|
2015-03-26 12:17:05 +01:00
|
|
|
intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_initial_plane_config *plane_config)
|
2014-03-07 08:57:48 -08:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2015-09-23 12:52:23 -03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-03-07 08:57:48 -08:00
|
|
|
struct drm_i915_gem_object *obj = NULL;
|
|
|
|
|
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
|
2015-02-05 17:22:18 +00:00
|
|
|
struct drm_framebuffer *fb = &plane_config->fb->base;
|
2015-02-10 23:12:27 +01:00
|
|
|
u32 base_aligned = round_down(plane_config->base, PAGE_SIZE);
|
|
|
|
|
u32 size_aligned = round_up(plane_config->base + plane_config->size,
|
|
|
|
|
PAGE_SIZE);
|
|
|
|
|
|
|
|
|
|
size_aligned -= base_aligned;
|
2014-03-07 08:57:48 -08:00
|
|
|
|
2014-03-10 08:07:02 +00:00
|
|
|
if (plane_config->size == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-09-23 12:52:23 -03:00
|
|
|
/* 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. */
|
2017-12-11 15:18:21 +00:00
|
|
|
if (size_aligned * 2 > dev_priv->stolen_usable_size)
|
2015-09-23 12:52:23 -03:00
|
|
|
return false;
|
|
|
|
|
|
2016-02-11 10:27:29 +00:00
|
|
|
mutex_lock(&dev->struct_mutex);
|
2016-12-01 14:16:36 +00:00
|
|
|
obj = i915_gem_object_create_stolen_for_preallocated(dev_priv,
|
2015-02-10 23:12:27 +01:00
|
|
|
base_aligned,
|
|
|
|
|
base_aligned,
|
|
|
|
|
size_aligned);
|
2017-02-15 10:59:18 +00:00
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
|
if (!obj)
|
2014-03-07 08:57:55 -08:00
|
|
|
return false;
|
2014-03-07 08:57:48 -08:00
|
|
|
|
2016-08-05 10:14:23 +01:00
|
|
|
if (plane_config->tiling == I915_TILING_X)
|
|
|
|
|
obj->tiling_and_stride = fb->pitches[0] | I915_TILING_X;
|
2014-03-07 08:57:48 -08:00
|
|
|
|
2016-12-14 23:32:55 +02:00
|
|
|
mode_cmd.pixel_format = fb->format->format;
|
2015-02-05 17:22:16 +00:00
|
|
|
mode_cmd.width = fb->width;
|
|
|
|
|
mode_cmd.height = fb->height;
|
|
|
|
|
mode_cmd.pitches[0] = fb->pitches[0];
|
2016-11-16 13:33:16 +02:00
|
|
|
mode_cmd.modifier[0] = fb->modifier;
|
2015-02-10 17:16:09 +00:00
|
|
|
mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
|
2014-03-07 08:57:48 -08:00
|
|
|
|
2017-02-15 10:59:18 +00:00
|
|
|
if (intel_framebuffer_init(to_intel_framebuffer(fb), obj, &mode_cmd)) {
|
2014-03-07 08:57:48 -08:00
|
|
|
DRM_DEBUG_KMS("intel fb init failed\n");
|
|
|
|
|
goto out_unref_obj;
|
|
|
|
|
}
|
2016-02-11 10:27:29 +00:00
|
|
|
|
2014-03-07 08:57:55 -08:00
|
|
|
|
2015-03-26 12:17:05 +01:00
|
|
|
DRM_DEBUG_KMS("initial plane fb obj %p\n", obj);
|
2014-03-07 08:57:55 -08:00
|
|
|
return true;
|
2014-03-07 08:57:48 -08:00
|
|
|
|
|
|
|
|
out_unref_obj:
|
2016-07-20 13:31:53 +01:00
|
|
|
i915_gem_object_put(obj);
|
2014-03-07 08:57:55 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-02 19:14:51 +02:00
|
|
|
static void
|
|
|
|
|
intel_set_plane_visible(struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state,
|
|
|
|
|
bool visible)
|
|
|
|
|
{
|
|
|
|
|
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
|
|
|
|
|
|
|
|
|
|
plane_state->base.visible = visible;
|
|
|
|
|
|
|
|
|
|
/* FIXME pre-g4x don't work like this */
|
|
|
|
|
if (visible) {
|
|
|
|
|
crtc_state->base.plane_mask |= BIT(drm_plane_index(&plane->base));
|
|
|
|
|
crtc_state->active_planes |= BIT(plane->id);
|
|
|
|
|
} else {
|
|
|
|
|
crtc_state->base.plane_mask &= ~BIT(drm_plane_index(&plane->base));
|
|
|
|
|
crtc_state->active_planes &= ~BIT(plane->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("%s active planes 0x%x\n",
|
|
|
|
|
crtc_state->base.crtc->name,
|
|
|
|
|
crtc_state->active_planes);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
static void intel_plane_disable_noatomic(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_plane *plane)
|
|
|
|
|
{
|
|
|
|
|
struct intel_crtc_state *crtc_state =
|
|
|
|
|
to_intel_crtc_state(crtc->base.state);
|
|
|
|
|
struct intel_plane_state *plane_state =
|
|
|
|
|
to_intel_plane_state(plane->base.state);
|
|
|
|
|
|
|
|
|
|
intel_set_plane_visible(crtc_state, plane_state, false);
|
|
|
|
|
|
|
|
|
|
if (plane->id == PLANE_PRIMARY)
|
|
|
|
|
intel_pre_disable_primary_noatomic(&crtc->base);
|
|
|
|
|
|
|
|
|
|
trace_intel_disable_plane(&plane->base, crtc);
|
|
|
|
|
plane->disable_plane(plane, crtc);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:52 +00:00
|
|
|
static void
|
2015-03-26 12:17:05 +01:00
|
|
|
intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
|
|
|
|
|
struct intel_initial_plane_config *plane_config)
|
2014-03-07 08:57:55 -08:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-03-07 08:57:55 -08:00
|
|
|
struct drm_crtc *c;
|
2014-07-08 07:50:07 -07:00
|
|
|
struct drm_i915_gem_object *obj;
|
2015-03-26 12:42:24 +01:00
|
|
|
struct drm_plane *primary = intel_crtc->base.primary;
|
2015-07-13 16:30:18 +02:00
|
|
|
struct drm_plane_state *plane_state = primary->state;
|
2015-12-03 11:37:36 -08:00
|
|
|
struct drm_crtc_state *crtc_state = intel_crtc->base.state;
|
|
|
|
|
struct intel_plane *intel_plane = to_intel_plane(primary);
|
2015-12-03 11:37:38 -08:00
|
|
|
struct intel_plane_state *intel_state =
|
|
|
|
|
to_intel_plane_state(plane_state);
|
2015-03-26 12:42:24 +01:00
|
|
|
struct drm_framebuffer *fb;
|
2014-03-07 08:57:55 -08:00
|
|
|
|
2015-02-05 17:22:18 +00:00
|
|
|
if (!plane_config->fb)
|
2014-03-07 08:57:55 -08:00
|
|
|
return;
|
|
|
|
|
|
2015-03-26 12:17:05 +01:00
|
|
|
if (intel_alloc_initial_plane_obj(intel_crtc, plane_config)) {
|
2015-03-26 12:42:24 +01:00
|
|
|
fb = &plane_config->fb->base;
|
|
|
|
|
goto valid_fb;
|
2015-02-05 18:30:20 +00:00
|
|
|
}
|
2014-03-07 08:57:55 -08:00
|
|
|
|
2015-02-05 17:22:18 +00:00
|
|
|
kfree(plane_config->fb);
|
2014-03-07 08:57:55 -08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Failed to alloc the obj, check to see if we should share
|
|
|
|
|
* an fb with another CRTC instead
|
|
|
|
|
*/
|
2014-05-13 23:32:24 +01:00
|
|
|
for_each_crtc(dev, c) {
|
2017-01-16 15:21:27 +00:00
|
|
|
struct intel_plane_state *state;
|
2014-03-07 08:57:55 -08:00
|
|
|
|
|
|
|
|
if (c == &intel_crtc->base)
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-01-16 15:21:27 +00:00
|
|
|
if (!to_intel_crtc(c)->active)
|
2014-07-08 07:50:07 -07:00
|
|
|
continue;
|
|
|
|
|
|
2017-01-16 15:21:27 +00:00
|
|
|
state = to_intel_plane_state(c->primary->state);
|
|
|
|
|
if (!state->vma)
|
2014-03-07 08:57:55 -08:00
|
|
|
continue;
|
|
|
|
|
|
2017-01-16 15:21:27 +00:00
|
|
|
if (intel_plane_ggtt_offset(state) == plane_config->base) {
|
|
|
|
|
fb = c->primary->fb;
|
2017-10-09 17:36:43 +05:30
|
|
|
drm_framebuffer_get(fb);
|
2015-03-26 12:42:24 +01:00
|
|
|
goto valid_fb;
|
2014-03-07 08:57:55 -08:00
|
|
|
}
|
|
|
|
|
}
|
2015-03-26 12:42:24 +01:00
|
|
|
|
2015-12-03 11:37:36 -08:00
|
|
|
/*
|
|
|
|
|
* We've failed to reconstruct the BIOS FB. Current display state
|
|
|
|
|
* indicates that the primary plane is visible, but has a NULL FB,
|
|
|
|
|
* which will lead to problems later if we don't fix it up. The
|
|
|
|
|
* simplest solution is to just disable the primary plane now and
|
|
|
|
|
* pretend the BIOS never had it enabled.
|
|
|
|
|
*/
|
2017-11-17 21:19:09 +02:00
|
|
|
intel_plane_disable_noatomic(intel_crtc, intel_plane);
|
2015-12-03 11:37:36 -08:00
|
|
|
|
2015-03-26 12:42:24 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
valid_fb:
|
2017-01-16 15:21:27 +00:00
|
|
|
mutex_lock(&dev->struct_mutex);
|
|
|
|
|
intel_state->vma =
|
|
|
|
|
intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
|
|
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
|
if (IS_ERR(intel_state->vma)) {
|
|
|
|
|
DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
|
|
|
|
|
intel_crtc->pipe, PTR_ERR(intel_state->vma));
|
|
|
|
|
|
|
|
|
|
intel_state->vma = NULL;
|
2017-10-09 17:36:43 +05:30
|
|
|
drm_framebuffer_put(fb);
|
2017-01-16 15:21:27 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-13 19:16:13 +02:00
|
|
|
plane_state->src_x = 0;
|
|
|
|
|
plane_state->src_y = 0;
|
2015-07-13 16:30:18 +02:00
|
|
|
plane_state->src_w = fb->width << 16;
|
|
|
|
|
plane_state->src_h = fb->height << 16;
|
|
|
|
|
|
2015-11-13 19:16:13 +02:00
|
|
|
plane_state->crtc_x = 0;
|
|
|
|
|
plane_state->crtc_y = 0;
|
2015-07-13 16:30:18 +02:00
|
|
|
plane_state->crtc_w = fb->width;
|
|
|
|
|
plane_state->crtc_h = fb->height;
|
|
|
|
|
|
2016-11-05 11:08:08 -04:00
|
|
|
intel_state->base.src = drm_plane_state_src(plane_state);
|
|
|
|
|
intel_state->base.dst = drm_plane_state_dest(plane_state);
|
2015-12-03 11:37:38 -08:00
|
|
|
|
2015-03-26 12:42:24 +01:00
|
|
|
obj = intel_fb_obj(fb);
|
2016-08-05 10:14:23 +01:00
|
|
|
if (i915_gem_object_is_tiled(obj))
|
2015-03-26 12:42:24 +01:00
|
|
|
dev_priv->preserve_bios_swizzle = true;
|
|
|
|
|
|
2017-10-09 17:36:43 +05:30
|
|
|
drm_framebuffer_get(fb);
|
2015-07-13 16:30:18 +02:00
|
|
|
primary->fb = primary->state->fb = fb;
|
2015-06-01 12:49:54 +02:00
|
|
|
primary->crtc = primary->state->crtc = &intel_crtc->base;
|
2017-03-02 19:14:51 +02:00
|
|
|
|
|
|
|
|
intel_set_plane_visible(to_intel_crtc_state(crtc_state),
|
|
|
|
|
to_intel_plane_state(plane_state),
|
|
|
|
|
true);
|
|
|
|
|
|
2016-08-04 16:32:37 +01:00
|
|
|
atomic_or(to_intel_plane(primary)->frontbuffer_bit,
|
|
|
|
|
&obj->frontbuffer_bits);
|
2014-03-07 08:57:48 -08:00
|
|
|
}
|
|
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane,
|
|
|
|
|
unsigned int rotation)
|
|
|
|
|
{
|
2016-12-14 23:30:57 +02:00
|
|
|
int cpp = fb->format->cpp[plane];
|
2016-01-28 16:53:54 +02:00
|
|
|
|
2016-11-16 13:33:16 +02:00
|
|
|
switch (fb->modifier) {
|
2017-03-24 14:29:48 -07:00
|
|
|
case DRM_FORMAT_MOD_LINEAR:
|
2016-01-28 16:53:54 +02:00
|
|
|
case I915_FORMAT_MOD_X_TILED:
|
|
|
|
|
switch (cpp) {
|
|
|
|
|
case 8:
|
|
|
|
|
return 4096;
|
|
|
|
|
case 4:
|
|
|
|
|
case 2:
|
|
|
|
|
case 1:
|
|
|
|
|
return 8192;
|
|
|
|
|
default:
|
|
|
|
|
MISSING_CASE(cpp);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED_CCS:
|
|
|
|
|
/* FIXME AUX plane? */
|
2016-01-28 16:53:54 +02:00
|
|
|
case I915_FORMAT_MOD_Y_TILED:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED:
|
|
|
|
|
switch (cpp) {
|
|
|
|
|
case 8:
|
|
|
|
|
return 2048;
|
|
|
|
|
case 4:
|
|
|
|
|
return 4096;
|
|
|
|
|
case 2:
|
|
|
|
|
case 1:
|
|
|
|
|
return 8192;
|
|
|
|
|
default:
|
|
|
|
|
MISSING_CASE(cpp);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2016-11-16 13:33:16 +02:00
|
|
|
MISSING_CASE(fb->modifier);
|
2016-01-28 16:53:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 2048;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
|
|
|
|
|
int main_x, int main_y, u32 main_offset)
|
|
|
|
|
{
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
int hsub = fb->format->hsub;
|
|
|
|
|
int vsub = fb->format->vsub;
|
|
|
|
|
int aux_x = plane_state->aux.x;
|
|
|
|
|
int aux_y = plane_state->aux.y;
|
|
|
|
|
u32 aux_offset = plane_state->aux.offset;
|
|
|
|
|
u32 alignment = intel_surf_alignment(fb, 1);
|
|
|
|
|
|
|
|
|
|
while (aux_offset >= main_offset && aux_y <= main_y) {
|
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
|
|
if (aux_x == main_x && aux_y == main_y)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (aux_offset == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
x = aux_x / hsub;
|
|
|
|
|
y = aux_y / vsub;
|
|
|
|
|
aux_offset = intel_adjust_tile_offset(&x, &y, plane_state, 1,
|
|
|
|
|
aux_offset, aux_offset - alignment);
|
|
|
|
|
aux_x = x * hsub + aux_x % hsub;
|
|
|
|
|
aux_y = y * vsub + aux_y % vsub;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aux_x != main_x || aux_y != main_y)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
plane_state->aux.offset = aux_offset;
|
|
|
|
|
plane_state->aux.x = aux_x;
|
|
|
|
|
plane_state->aux.y = aux_y;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 13:24:14 +02:00
|
|
|
static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state)
|
2016-01-28 16:53:54 +02:00
|
|
|
{
|
2018-01-16 13:24:14 +02:00
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
2016-01-28 16:53:54 +02:00
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
unsigned int rotation = plane_state->base.rotation;
|
2016-08-15 10:41:47 +02:00
|
|
|
int x = plane_state->base.src.x1 >> 16;
|
|
|
|
|
int y = plane_state->base.src.y1 >> 16;
|
|
|
|
|
int w = drm_rect_width(&plane_state->base.src) >> 16;
|
|
|
|
|
int h = drm_rect_height(&plane_state->base.src) >> 16;
|
2018-01-16 13:24:14 +02:00
|
|
|
int dst_x = plane_state->base.dst.x1;
|
|
|
|
|
int pipe_src_w = crtc_state->pipe_src_w;
|
2016-01-28 16:53:54 +02:00
|
|
|
int max_width = skl_max_plane_width(fb, 0, rotation);
|
|
|
|
|
int max_height = 4096;
|
2016-01-28 16:30:28 +02:00
|
|
|
u32 alignment, offset, aux_offset = plane_state->aux.offset;
|
2016-01-28 16:53:54 +02:00
|
|
|
|
|
|
|
|
if (w > max_width || h > max_height) {
|
|
|
|
|
DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
|
|
|
|
|
w, h, max_width, max_height);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 13:24:14 +02:00
|
|
|
/*
|
|
|
|
|
* Display WA #1175: cnl,glk
|
|
|
|
|
* Planes other than the cursor may cause FIFO underflow and display
|
|
|
|
|
* corruption if starting less than 4 pixels from the right edge of
|
|
|
|
|
* the screen.
|
2018-01-16 13:24:15 +02:00
|
|
|
* Besides the above WA fix the similar problem, where planes other
|
|
|
|
|
* than the cursor ending less than 4 pixels from the left edge of the
|
|
|
|
|
* screen may cause FIFO underflow and display corruption.
|
2018-01-16 13:24:14 +02:00
|
|
|
*/
|
|
|
|
|
if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
|
2018-01-16 13:24:15 +02:00
|
|
|
(dst_x + w < 4 || dst_x > pipe_src_w - 4)) {
|
|
|
|
|
DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n",
|
|
|
|
|
dst_x + w < 4 ? "end" : "start",
|
|
|
|
|
dst_x + w < 4 ? dst_x + w : dst_x,
|
|
|
|
|
4, pipe_src_w - 4);
|
2018-01-16 13:24:14 +02:00
|
|
|
return -ERANGE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
intel_add_fb_offsets(&x, &y, plane_state, 0);
|
|
|
|
|
offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
|
2017-03-07 21:42:06 +02:00
|
|
|
alignment = intel_surf_alignment(fb, 0);
|
2016-01-28 16:53:54 +02:00
|
|
|
|
2016-01-28 16:30:28 +02:00
|
|
|
/*
|
|
|
|
|
* AUX surface offset is specified as the distance from the
|
|
|
|
|
* main surface offset, and it must be non-negative. Make
|
|
|
|
|
* sure that is what we will get.
|
|
|
|
|
*/
|
|
|
|
|
if (offset > aux_offset)
|
|
|
|
|
offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
|
|
|
|
|
offset, aux_offset & ~(alignment - 1));
|
|
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
/*
|
|
|
|
|
* When using an X-tiled surface, the plane blows up
|
|
|
|
|
* if the x offset + width exceed the stride.
|
|
|
|
|
*
|
|
|
|
|
* TODO: linear and Y-tiled seem fine, Yf untested,
|
|
|
|
|
*/
|
2016-11-16 13:33:16 +02:00
|
|
|
if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
|
2016-12-14 23:30:57 +02:00
|
|
|
int cpp = fb->format->cpp[0];
|
2016-01-28 16:53:54 +02:00
|
|
|
|
|
|
|
|
while ((x + w) * cpp > fb->pitches[0]) {
|
|
|
|
|
if (offset == 0) {
|
2017-08-01 09:58:13 -07:00
|
|
|
DRM_DEBUG_KMS("Unable to find suitable display surface offset due to X-tiling\n");
|
2016-01-28 16:53:54 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
|
|
|
|
|
offset, offset - alignment);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
/*
|
|
|
|
|
* CCS AUX surface doesn't have its own x/y offsets, we must make sure
|
|
|
|
|
* they match with the main surface x/y offsets.
|
|
|
|
|
*/
|
|
|
|
|
if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
|
|
|
|
|
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
|
|
|
|
|
while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) {
|
|
|
|
|
if (offset == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
|
|
|
|
|
offset, offset - alignment);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x != plane_state->aux.x || y != plane_state->aux.y) {
|
|
|
|
|
DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
plane_state->main.offset = offset;
|
|
|
|
|
plane_state->main.x = x;
|
|
|
|
|
plane_state->main.y = y;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 16:30:28 +02:00
|
|
|
static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
unsigned int rotation = plane_state->base.rotation;
|
|
|
|
|
int max_width = skl_max_plane_width(fb, 1, rotation);
|
|
|
|
|
int max_height = 4096;
|
2016-08-15 10:41:47 +02:00
|
|
|
int x = plane_state->base.src.x1 >> 17;
|
|
|
|
|
int y = plane_state->base.src.y1 >> 17;
|
|
|
|
|
int w = drm_rect_width(&plane_state->base.src) >> 17;
|
|
|
|
|
int h = drm_rect_height(&plane_state->base.src) >> 17;
|
2016-01-28 16:30:28 +02:00
|
|
|
u32 offset;
|
|
|
|
|
|
|
|
|
|
intel_add_fb_offsets(&x, &y, plane_state, 1);
|
|
|
|
|
offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
|
|
|
|
|
|
|
|
|
|
/* FIXME not quite sure how/if these apply to the chroma plane */
|
|
|
|
|
if (w > max_width || h > max_height) {
|
|
|
|
|
DRM_DEBUG_KMS("CbCr source size %dx%d too big (limit %dx%d)\n",
|
|
|
|
|
w, h, max_width, max_height);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plane_state->aux.offset = offset;
|
|
|
|
|
plane_state->aux.x = x;
|
|
|
|
|
plane_state->aux.y = y;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
|
2017-12-22 21:22:28 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
2017-08-01 09:58:13 -07:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(plane_state->base.crtc);
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
int src_x = plane_state->base.src.x1 >> 16;
|
|
|
|
|
int src_y = plane_state->base.src.y1 >> 16;
|
|
|
|
|
int hsub = fb->format->hsub;
|
|
|
|
|
int vsub = fb->format->vsub;
|
|
|
|
|
int x = src_x / hsub;
|
|
|
|
|
int y = src_y / vsub;
|
|
|
|
|
u32 offset;
|
|
|
|
|
|
2017-12-22 21:22:28 +02:00
|
|
|
if (!skl_plane_has_ccs(dev_priv, crtc->pipe, plane->id)) {
|
|
|
|
|
DRM_DEBUG_KMS("No RC support on %s\n", plane->base.name);
|
2017-08-01 09:58:13 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) {
|
|
|
|
|
DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n",
|
|
|
|
|
plane_state->base.rotation);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
intel_add_fb_offsets(&x, &y, plane_state, 1);
|
|
|
|
|
offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
|
|
|
|
|
|
|
|
|
|
plane_state->aux.offset = offset;
|
|
|
|
|
plane_state->aux.x = x * hsub + src_x % hsub;
|
|
|
|
|
plane_state->aux.y = y * vsub + src_y % vsub;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 13:24:14 +02:00
|
|
|
int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state)
|
2016-01-28 16:53:54 +02:00
|
|
|
{
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
unsigned int rotation = plane_state->base.rotation;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2017-12-15 13:38:00 -08:00
|
|
|
if (rotation & DRM_MODE_REFLECT_X &&
|
|
|
|
|
fb->modifier == DRM_FORMAT_MOD_LINEAR) {
|
|
|
|
|
DRM_DEBUG_KMS("horizontal flip is not supported with linear surface formats\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-07 22:20:54 +02:00
|
|
|
if (!plane_state->base.visible)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
/* Rotate src coordinates to match rotated GTT view */
|
2016-09-26 19:30:46 +03:00
|
|
|
if (drm_rotation_90_or_270(rotation))
|
2016-08-15 10:41:47 +02:00
|
|
|
drm_rect_rotate(&plane_state->base.src,
|
2016-10-24 19:13:04 +03:00
|
|
|
fb->width << 16, fb->height << 16,
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_270);
|
2016-01-28 16:53:54 +02:00
|
|
|
|
2016-01-28 16:30:28 +02:00
|
|
|
/*
|
|
|
|
|
* Handle the AUX surface first since
|
|
|
|
|
* the main surface setup depends on it.
|
|
|
|
|
*/
|
2016-12-14 23:32:55 +02:00
|
|
|
if (fb->format->format == DRM_FORMAT_NV12) {
|
2016-01-28 16:30:28 +02:00
|
|
|
ret = skl_check_nv12_aux_surface(plane_state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2017-08-01 09:58:13 -07:00
|
|
|
} else if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
|
|
|
|
|
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) {
|
|
|
|
|
ret = skl_check_ccs_aux_surface(plane_state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2016-01-28 16:30:28 +02:00
|
|
|
} else {
|
|
|
|
|
plane_state->aux.offset = ~0xfff;
|
|
|
|
|
plane_state->aux.x = 0;
|
|
|
|
|
plane_state->aux.y = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-16 13:24:14 +02:00
|
|
|
ret = skl_check_main_surface(crtc_state, plane_state);
|
2016-01-28 16:53:54 +02:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-23 21:27:07 +02:00
|
|
|
static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *plane_state)
|
2010-08-02 12:07:50 -07:00
|
|
|
{
|
2017-03-23 21:27:07 +02:00
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
|
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
2016-02-15 22:54:41 +02:00
|
|
|
unsigned int rotation = plane_state->base.rotation;
|
2017-03-23 21:27:07 +02:00
|
|
|
u32 dspcntr;
|
2014-08-27 17:48:41 +03:00
|
|
|
|
2017-03-23 21:27:07 +02:00
|
|
|
dspcntr = DISPLAY_PLANE_ENABLE | DISPPLANE_GAMMA_ENABLE;
|
2014-08-08 21:51:10 +03:00
|
|
|
|
2017-03-23 21:27:08 +02:00
|
|
|
if (IS_G4X(dev_priv) || IS_GEN5(dev_priv) ||
|
|
|
|
|
IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv))
|
2017-03-23 21:27:07 +02:00
|
|
|
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
2014-08-08 21:51:10 +03:00
|
|
|
|
2017-03-23 21:27:08 +02:00
|
|
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
|
|
|
|
|
dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
|
2014-08-08 21:51:10 +03:00
|
|
|
|
2017-03-27 21:55:32 +03:00
|
|
|
if (INTEL_GEN(dev_priv) < 4)
|
|
|
|
|
dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
|
2010-08-02 12:07:50 -07:00
|
|
|
|
2016-12-14 23:32:55 +02:00
|
|
|
switch (fb->format->format) {
|
2012-10-31 17:50:14 +02:00
|
|
|
case DRM_FORMAT_C8:
|
2010-08-02 12:07:50 -07:00
|
|
|
dspcntr |= DISPPLANE_8BPP;
|
|
|
|
|
break;
|
2012-10-31 17:50:14 +02:00
|
|
|
case DRM_FORMAT_XRGB1555:
|
|
|
|
|
dspcntr |= DISPPLANE_BGRX555;
|
2010-08-02 12:07:50 -07:00
|
|
|
break;
|
2012-10-31 17:50:14 +02:00
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
dspcntr |= DISPPLANE_BGRX565;
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
dspcntr |= DISPPLANE_BGRX888;
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
|
|
dspcntr |= DISPPLANE_RGBX888;
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_XRGB2101010:
|
|
|
|
|
dspcntr |= DISPPLANE_BGRX101010;
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_XBGR2101010:
|
|
|
|
|
dspcntr |= DISPPLANE_RGBX101010;
|
2010-08-02 12:07:50 -07:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-03-23 21:27:07 +02:00
|
|
|
MISSING_CASE(fb->format->format);
|
|
|
|
|
return 0;
|
2010-08-02 12:07:50 -07:00
|
|
|
}
|
2012-10-31 17:50:14 +02:00
|
|
|
|
2016-02-04 20:38:20 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4 &&
|
2016-11-16 13:33:16 +02:00
|
|
|
fb->modifier == I915_FORMAT_MOD_X_TILED)
|
2014-08-08 21:51:10 +03:00
|
|
|
dspcntr |= DISPPLANE_TILED;
|
2010-08-02 12:07:50 -07:00
|
|
|
|
2017-05-19 16:50:17 -04:00
|
|
|
if (rotation & DRM_MODE_ROTATE_180)
|
2016-11-14 18:53:59 +02:00
|
|
|
dspcntr |= DISPPLANE_ROTATE_180;
|
|
|
|
|
|
2017-05-19 16:50:17 -04:00
|
|
|
if (rotation & DRM_MODE_REFLECT_X)
|
2016-11-14 18:54:00 +02:00
|
|
|
dspcntr |= DISPPLANE_MIRROR;
|
|
|
|
|
|
2017-03-23 21:27:07 +02:00
|
|
|
return dspcntr;
|
|
|
|
|
}
|
2013-06-07 10:47:01 +03:00
|
|
|
|
2017-03-23 21:27:12 +02:00
|
|
|
int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
|
2017-03-23 21:27:10 +02:00
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
|
|
|
|
int src_x = plane_state->base.src.x1 >> 16;
|
|
|
|
|
int src_y = plane_state->base.src.y1 >> 16;
|
|
|
|
|
u32 offset;
|
2010-08-02 12:07:50 -07:00
|
|
|
|
2017-03-23 21:27:10 +02:00
|
|
|
intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
|
2012-07-05 12:17:29 +02:00
|
|
|
|
2017-03-23 21:27:10 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
|
|
|
|
offset = intel_compute_tile_offset(&src_x, &src_y,
|
|
|
|
|
plane_state, 0);
|
|
|
|
|
else
|
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
|
|
/* HSW/BDW do this automagically in hardware */
|
|
|
|
|
if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {
|
|
|
|
|
unsigned int rotation = plane_state->base.rotation;
|
|
|
|
|
int src_w = drm_rect_width(&plane_state->base.src) >> 16;
|
|
|
|
|
int src_h = drm_rect_height(&plane_state->base.src) >> 16;
|
|
|
|
|
|
2017-05-19 16:50:17 -04:00
|
|
|
if (rotation & DRM_MODE_ROTATE_180) {
|
2017-03-23 21:27:10 +02:00
|
|
|
src_x += src_w - 1;
|
|
|
|
|
src_y += src_h - 1;
|
2017-05-19 16:50:17 -04:00
|
|
|
} else if (rotation & DRM_MODE_REFLECT_X) {
|
2017-03-23 21:27:10 +02:00
|
|
|
src_x += src_w - 1;
|
|
|
|
|
}
|
2014-08-22 14:06:04 +05:30
|
|
|
}
|
|
|
|
|
|
2017-03-23 21:27:10 +02:00
|
|
|
plane_state->main.offset = offset;
|
|
|
|
|
plane_state->main.x = src_x;
|
|
|
|
|
plane_state->main.y = src_y;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
static void i9xx_update_plane(struct intel_plane *plane,
|
|
|
|
|
const struct intel_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *plane_state)
|
2017-03-23 21:27:07 +02:00
|
|
|
{
|
2017-11-17 21:19:10 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
2017-03-27 21:55:33 +03:00
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
2017-11-17 21:19:10 +02:00
|
|
|
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
|
2017-03-23 21:27:07 +02:00
|
|
|
u32 linear_offset;
|
2017-03-23 21:27:09 +02:00
|
|
|
u32 dspcntr = plane_state->ctl;
|
2017-11-17 21:19:10 +02:00
|
|
|
i915_reg_t reg = DSPCNTR(i9xx_plane);
|
2017-03-23 21:27:10 +02:00
|
|
|
int x = plane_state->main.x;
|
|
|
|
|
int y = plane_state->main.y;
|
2017-03-23 21:27:07 +02:00
|
|
|
unsigned long irqflags;
|
2017-10-17 23:08:08 +03:00
|
|
|
u32 dspaddr_offset;
|
2017-03-23 21:27:07 +02:00
|
|
|
|
2016-01-20 18:02:50 +02:00
|
|
|
linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2017-03-23 21:27:10 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
2017-10-17 23:08:08 +03:00
|
|
|
dspaddr_offset = plane_state->main.offset;
|
2017-03-23 21:27:10 +02:00
|
|
|
else
|
2017-10-17 23:08:08 +03:00
|
|
|
dspaddr_offset = linear_offset;
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
|
2017-03-09 17:44:33 +02:00
|
|
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
|
|
|
|
|
2017-03-09 17:44:32 +02:00
|
|
|
if (INTEL_GEN(dev_priv) < 4) {
|
|
|
|
|
/* pipesrc and dspsize control the size that is scaled from,
|
|
|
|
|
* which should always be the user's requested size.
|
|
|
|
|
*/
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPSIZE(i9xx_plane),
|
2017-03-09 17:44:33 +02:00
|
|
|
((crtc_state->pipe_src_h - 1) << 16) |
|
|
|
|
|
(crtc_state->pipe_src_w - 1));
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPPOS(i9xx_plane), 0);
|
|
|
|
|
} else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
|
|
|
|
|
I915_WRITE_FW(PRIMSIZE(i9xx_plane),
|
2017-03-09 17:44:33 +02:00
|
|
|
((crtc_state->pipe_src_h - 1) << 16) |
|
|
|
|
|
(crtc_state->pipe_src_w - 1));
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(PRIMPOS(i9xx_plane), 0);
|
|
|
|
|
I915_WRITE_FW(PRIMCNSTALPHA(i9xx_plane), 0);
|
2017-03-09 17:44:32 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-09 17:44:33 +02:00
|
|
|
I915_WRITE_FW(reg, dspcntr);
|
2014-08-22 14:06:04 +05:30
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPSTRIDE(i9xx_plane), fb->pitches[0]);
|
2017-03-23 21:27:11 +02:00
|
|
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPSURF(i9xx_plane),
|
2017-03-23 21:27:11 +02:00
|
|
|
intel_plane_ggtt_offset(plane_state) +
|
2017-10-17 23:08:08 +03:00
|
|
|
dspaddr_offset);
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPOFFSET(i9xx_plane), (y << 16) | x);
|
2017-03-23 21:27:11 +02:00
|
|
|
} else if (INTEL_GEN(dev_priv) >= 4) {
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPSURF(i9xx_plane),
|
2017-03-09 17:44:33 +02:00
|
|
|
intel_plane_ggtt_offset(plane_state) +
|
2017-10-17 23:08:08 +03:00
|
|
|
dspaddr_offset);
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPTILEOFF(i9xx_plane), (y << 16) | x);
|
|
|
|
|
I915_WRITE_FW(DSPLINOFF(i9xx_plane), linear_offset);
|
2016-11-07 22:20:57 +02:00
|
|
|
} else {
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPADDR(i9xx_plane),
|
2017-03-09 17:44:33 +02:00
|
|
|
intel_plane_ggtt_offset(plane_state) +
|
2017-10-17 23:08:08 +03:00
|
|
|
dspaddr_offset);
|
2016-11-07 22:20:57 +02:00
|
|
|
}
|
2017-03-09 17:44:33 +02:00
|
|
|
POSTING_READ_FW(reg);
|
|
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
2011-06-24 12:19:23 -07:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
static void i9xx_disable_plane(struct intel_plane *plane,
|
|
|
|
|
struct intel_crtc *crtc)
|
2011-06-24 12:19:23 -07:00
|
|
|
{
|
2017-11-17 21:19:10 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
|
|
|
|
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
|
2017-03-09 17:44:33 +02:00
|
|
|
unsigned long irqflags;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
2014-08-08 21:51:10 +03:00
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPCNTR(i9xx_plane), 0);
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
|
|
|
|
I915_WRITE_FW(DSPSURF(i9xx_plane), 0);
|
2016-01-07 11:54:11 +01:00
|
|
|
else
|
2017-11-17 21:19:10 +02:00
|
|
|
I915_WRITE_FW(DSPADDR(i9xx_plane), 0);
|
|
|
|
|
POSTING_READ_FW(DSPCNTR(i9xx_plane));
|
2017-03-09 17:44:33 +02:00
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
2016-01-07 11:54:11 +01:00
|
|
|
}
|
2014-08-27 17:48:41 +03:00
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
static bool i9xx_plane_get_hw_state(struct intel_plane *plane)
|
2017-11-17 21:19:08 +02:00
|
|
|
{
|
2017-11-17 21:19:10 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
2017-11-17 21:19:08 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
2017-11-17 21:19:10 +02:00
|
|
|
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
|
|
|
|
|
enum pipe pipe = plane->pipe;
|
2017-11-17 21:19:08 +02:00
|
|
|
bool ret;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Not 100% correct for planes that can move between pipes,
|
|
|
|
|
* but that's only the case for gen2-4 which don't have any
|
|
|
|
|
* display power wells.
|
|
|
|
|
*/
|
|
|
|
|
power_domain = POWER_DOMAIN_PIPE(pipe);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
ret = I915_READ(DSPCNTR(i9xx_plane)) & DISPLAY_PLANE_ENABLE;
|
2017-11-17 21:19:08 +02:00
|
|
|
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
static u32
|
|
|
|
|
intel_fb_stride_alignment(const struct drm_framebuffer *fb, int plane)
|
2015-02-27 11:15:18 +00:00
|
|
|
{
|
2017-03-24 14:29:48 -07:00
|
|
|
if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
|
2015-02-27 11:15:18 +00:00
|
|
|
return 64;
|
2017-03-07 21:42:06 +02:00
|
|
|
else
|
|
|
|
|
return intel_tile_width_bytes(fb, plane);
|
2015-02-27 11:15:18 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-13 16:30:15 +02:00
|
|
|
static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-07-13 16:30:15 +02:00
|
|
|
|
|
|
|
|
I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, id), 0);
|
|
|
|
|
I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, id), 0);
|
|
|
|
|
I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0);
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-07 15:28:45 -07:00
|
|
|
/*
|
|
|
|
|
* This function detaches (aka. unbinds) unused scalers in hardware
|
|
|
|
|
*/
|
2015-06-15 12:33:48 +02:00
|
|
|
static void skl_detach_scalers(struct intel_crtc *intel_crtc)
|
2015-04-07 15:28:45 -07:00
|
|
|
{
|
|
|
|
|
struct intel_crtc_scaler_state *scaler_state;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
scaler_state = &intel_crtc->config->scaler_state;
|
|
|
|
|
|
|
|
|
|
/* loop through and disable scalers that aren't in use */
|
|
|
|
|
for (i = 0; i < intel_crtc->num_scalers; i++) {
|
2015-07-13 16:30:15 +02:00
|
|
|
if (!scaler_state->scalers[i].in_use)
|
|
|
|
|
skl_detach_scaler(intel_crtc, i);
|
2015-04-07 15:28:45 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-28 18:33:11 +02:00
|
|
|
u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
|
|
|
|
|
unsigned int rotation)
|
|
|
|
|
{
|
2017-03-07 21:42:08 +02:00
|
|
|
u32 stride;
|
|
|
|
|
|
|
|
|
|
if (plane >= fb->format->num_planes)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
stride = intel_fb_pitch(fb, plane, rotation);
|
2016-01-28 18:33:11 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The stride is either expressed as a multiple of 64 bytes chunks for
|
|
|
|
|
* linear buffers or in number of tiles for tiled buffers.
|
|
|
|
|
*/
|
2017-03-07 21:42:06 +02:00
|
|
|
if (drm_rotation_90_or_270(rotation))
|
|
|
|
|
stride /= intel_tile_height(fb, plane);
|
|
|
|
|
else
|
|
|
|
|
stride /= intel_fb_stride_alignment(fb, plane);
|
2016-01-28 18:33:11 +02:00
|
|
|
|
|
|
|
|
return stride;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 23:17:56 +02:00
|
|
|
static u32 skl_plane_ctl_format(uint32_t pixel_format)
|
2013-07-03 21:06:04 +01:00
|
|
|
{
|
2015-04-27 13:48:39 -07:00
|
|
|
switch (pixel_format) {
|
2015-05-12 16:13:17 +01:00
|
|
|
case DRM_FORMAT_C8:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_INDEXED;
|
2013-07-03 21:06:04 +01:00
|
|
|
case DRM_FORMAT_RGB565:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_RGB_565;
|
2013-07-03 21:06:04 +01:00
|
|
|
case DRM_FORMAT_XBGR8888:
|
2017-11-13 10:11:28 -08:00
|
|
|
case DRM_FORMAT_ABGR8888:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
|
2015-04-27 13:48:39 -07:00
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
2017-11-13 10:11:28 -08:00
|
|
|
return PLANE_CTL_FORMAT_XRGB_8888;
|
2013-07-03 21:06:04 +01:00
|
|
|
case DRM_FORMAT_XRGB2101010:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_XRGB_2101010;
|
2013-07-03 21:06:04 +01:00
|
|
|
case DRM_FORMAT_XBGR2101010:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_ORDER_RGBX | PLANE_CTL_FORMAT_XRGB_2101010;
|
2015-04-27 13:48:39 -07:00
|
|
|
case DRM_FORMAT_YUYV:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV;
|
2015-04-27 13:48:39 -07:00
|
|
|
case DRM_FORMAT_YVYU:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU;
|
2015-04-27 13:48:39 -07:00
|
|
|
case DRM_FORMAT_UYVY:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY;
|
2015-04-27 13:48:39 -07:00
|
|
|
case DRM_FORMAT_VYUY:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY;
|
2013-07-03 21:06:04 +01:00
|
|
|
default:
|
2015-05-12 16:13:16 +01:00
|
|
|
MISSING_CASE(pixel_format);
|
2013-07-03 21:06:04 +01:00
|
|
|
}
|
2015-05-12 16:13:14 +01:00
|
|
|
|
2015-05-15 15:07:02 +01:00
|
|
|
return 0;
|
2015-04-27 13:48:39 -07:00
|
|
|
}
|
2013-07-03 21:06:04 +01:00
|
|
|
|
2017-11-13 10:11:28 -08:00
|
|
|
/*
|
|
|
|
|
* XXX: For ARBG/ABGR formats we default to expecting scanout buffers
|
|
|
|
|
* to be already pre-multiplied. We need to add a knob (or a different
|
|
|
|
|
* DRM_FORMAT) for user-space to configure that.
|
|
|
|
|
*/
|
|
|
|
|
static u32 skl_plane_ctl_alpha(uint32_t pixel_format)
|
|
|
|
|
{
|
|
|
|
|
switch (pixel_format) {
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
|
return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
|
|
|
|
|
default:
|
|
|
|
|
return PLANE_CTL_ALPHA_DISABLE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 glk_plane_color_ctl_alpha(uint32_t pixel_format)
|
|
|
|
|
{
|
|
|
|
|
switch (pixel_format) {
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
|
return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
|
|
|
|
|
default:
|
|
|
|
|
return PLANE_COLOR_ALPHA_DISABLE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 23:17:56 +02:00
|
|
|
static u32 skl_plane_ctl_tiling(uint64_t fb_modifier)
|
2015-04-27 13:48:39 -07:00
|
|
|
{
|
|
|
|
|
switch (fb_modifier) {
|
2017-03-24 14:29:48 -07:00
|
|
|
case DRM_FORMAT_MOD_LINEAR:
|
2013-07-03 21:06:04 +01:00
|
|
|
break;
|
2015-02-10 17:16:11 +00:00
|
|
|
case I915_FORMAT_MOD_X_TILED:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_TILED_X;
|
2015-02-27 11:15:18 +00:00
|
|
|
case I915_FORMAT_MOD_Y_TILED:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_TILED_Y;
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
|
|
|
|
return PLANE_CTL_TILED_Y | PLANE_CTL_DECOMPRESSION_ENABLE;
|
2015-02-27 11:15:18 +00:00
|
|
|
case I915_FORMAT_MOD_Yf_TILED:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_TILED_YF;
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Yf_TILED_CCS:
|
|
|
|
|
return PLANE_CTL_TILED_YF | PLANE_CTL_DECOMPRESSION_ENABLE;
|
2013-07-03 21:06:04 +01:00
|
|
|
default:
|
2015-04-27 13:48:39 -07:00
|
|
|
MISSING_CASE(fb_modifier);
|
2013-07-03 21:06:04 +01:00
|
|
|
}
|
2015-05-12 16:13:14 +01:00
|
|
|
|
2015-05-15 15:07:02 +01:00
|
|
|
return 0;
|
2015-04-27 13:48:39 -07:00
|
|
|
}
|
2013-07-03 21:06:04 +01:00
|
|
|
|
2017-12-15 13:38:00 -08:00
|
|
|
static u32 skl_plane_ctl_rotate(unsigned int rotate)
|
2015-04-27 13:48:39 -07:00
|
|
|
{
|
2017-12-15 13:38:00 -08:00
|
|
|
switch (rotate) {
|
2017-05-19 16:50:17 -04:00
|
|
|
case DRM_MODE_ROTATE_0:
|
2015-04-27 13:48:39 -07:00
|
|
|
break;
|
2015-05-20 13:40:48 +05:30
|
|
|
/*
|
2017-05-19 16:50:17 -04:00
|
|
|
* DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
|
2015-05-20 13:40:48 +05:30
|
|
|
* while i915 HW rotation is clockwise, thats why this swapping.
|
|
|
|
|
*/
|
2017-05-19 16:50:17 -04:00
|
|
|
case DRM_MODE_ROTATE_90:
|
2015-05-20 13:40:48 +05:30
|
|
|
return PLANE_CTL_ROTATE_270;
|
2017-05-19 16:50:17 -04:00
|
|
|
case DRM_MODE_ROTATE_180:
|
2015-05-15 15:07:02 +01:00
|
|
|
return PLANE_CTL_ROTATE_180;
|
2017-05-19 16:50:17 -04:00
|
|
|
case DRM_MODE_ROTATE_270:
|
2015-05-20 13:40:48 +05:30
|
|
|
return PLANE_CTL_ROTATE_90;
|
2015-04-27 13:48:39 -07:00
|
|
|
default:
|
2017-12-15 13:38:00 -08:00
|
|
|
MISSING_CASE(rotate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 cnl_plane_ctl_flip(unsigned int reflect)
|
|
|
|
|
{
|
|
|
|
|
switch (reflect) {
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
case DRM_MODE_REFLECT_X:
|
|
|
|
|
return PLANE_CTL_FLIP_HORIZONTAL;
|
|
|
|
|
case DRM_MODE_REFLECT_Y:
|
|
|
|
|
default:
|
|
|
|
|
MISSING_CASE(reflect);
|
2015-04-27 13:48:39 -07:00
|
|
|
}
|
|
|
|
|
|
2015-05-15 15:07:02 +01:00
|
|
|
return 0;
|
2015-04-27 13:48:39 -07:00
|
|
|
}
|
|
|
|
|
|
2017-03-17 23:17:56 +02:00
|
|
|
u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *plane_state)
|
2017-03-17 23:17:55 +02:00
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
unsigned int rotation = plane_state->base.rotation;
|
2017-03-17 23:17:56 +02:00
|
|
|
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
|
2017-03-17 23:17:55 +02:00
|
|
|
u32 plane_ctl;
|
|
|
|
|
|
|
|
|
|
plane_ctl = PLANE_CTL_ENABLE;
|
|
|
|
|
|
2017-11-13 10:11:28 -08:00
|
|
|
if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
|
|
|
|
|
plane_ctl |= skl_plane_ctl_alpha(fb->format->format);
|
2017-03-17 23:17:55 +02:00
|
|
|
plane_ctl |=
|
|
|
|
|
PLANE_CTL_PIPE_GAMMA_ENABLE |
|
|
|
|
|
PLANE_CTL_PIPE_CSC_ENABLE |
|
|
|
|
|
PLANE_CTL_PLANE_GAMMA_DISABLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plane_ctl |= skl_plane_ctl_format(fb->format->format);
|
|
|
|
|
plane_ctl |= skl_plane_ctl_tiling(fb->modifier);
|
2017-12-15 13:38:00 -08:00
|
|
|
plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK);
|
|
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 10)
|
|
|
|
|
plane_ctl |= cnl_plane_ctl_flip(rotation &
|
|
|
|
|
DRM_MODE_REFLECT_MASK);
|
2017-03-17 23:17:55 +02:00
|
|
|
|
2017-03-17 23:17:56 +02:00
|
|
|
if (key->flags & I915_SET_COLORKEY_DESTINATION)
|
|
|
|
|
plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
|
|
|
|
|
else if (key->flags & I915_SET_COLORKEY_SOURCE)
|
|
|
|
|
plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
|
|
|
|
|
|
2017-03-17 23:17:55 +02:00
|
|
|
return plane_ctl;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-13 10:11:28 -08:00
|
|
|
u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
u32 plane_color_ctl = 0;
|
|
|
|
|
|
|
|
|
|
plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE;
|
|
|
|
|
plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
|
|
|
|
|
plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
|
|
|
|
|
plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format);
|
|
|
|
|
|
|
|
|
|
return plane_color_ctl;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
static int
|
|
|
|
|
__intel_display_resume(struct drm_device *dev,
|
2017-01-16 10:37:38 +01:00
|
|
|
struct drm_atomic_state *state,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
2016-08-05 23:28:27 +03:00
|
|
|
{
|
|
|
|
|
struct drm_crtc_state *crtc_state;
|
|
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
int i, ret;
|
2015-09-10 16:07:58 +02:00
|
|
|
|
2017-06-01 17:36:13 +03:00
|
|
|
intel_modeset_setup_hw_state(dev, ctx);
|
2016-11-16 08:55:39 +00:00
|
|
|
i915_redisable_vga(to_i915(dev));
|
2016-08-05 23:28:27 +03:00
|
|
|
|
|
|
|
|
if (!state)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
/*
|
|
|
|
|
* We've duplicated the state, pointers to the old state are invalid.
|
|
|
|
|
*
|
|
|
|
|
* Don't attempt to use the old state until we commit the duplicated state.
|
|
|
|
|
*/
|
|
|
|
|
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
2016-08-05 23:28:27 +03:00
|
|
|
/*
|
|
|
|
|
* Force recalculation even if we restore
|
|
|
|
|
* current state. With fast modeset this may not result
|
|
|
|
|
* in a modeset when the state is compatible.
|
|
|
|
|
*/
|
|
|
|
|
crtc_state->mode_changed = true;
|
2013-02-18 19:08:49 +02:00
|
|
|
}
|
2016-08-05 23:28:27 +03:00
|
|
|
|
|
|
|
|
/* ignore any reset values/BIOS leftovers in the WM registers */
|
2017-03-02 19:15:02 +02:00
|
|
|
if (!HAS_GMCH_DISPLAY(to_i915(dev)))
|
|
|
|
|
to_intel_atomic_state(state)->skip_intermediate_wm = true;
|
2016-08-05 23:28:27 +03:00
|
|
|
|
2017-01-16 10:37:38 +01:00
|
|
|
ret = drm_atomic_helper_commit_duplicated_state(state, ctx);
|
2016-08-05 23:28:27 +03:00
|
|
|
|
|
|
|
|
WARN_ON(ret == -EDEADLK);
|
|
|
|
|
return ret;
|
2013-02-18 19:08:49 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-05 23:28:29 +03:00
|
|
|
static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
2016-08-05 23:28:30 +03:00
|
|
|
return intel_has_gpu_reset(dev_priv) &&
|
|
|
|
|
INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv);
|
2016-08-05 23:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2016-05-06 15:40:21 +01:00
|
|
|
void intel_prepare_reset(struct drm_i915_private *dev_priv)
|
2014-11-24 18:28:11 +02:00
|
|
|
{
|
2016-08-05 23:28:27 +03:00
|
|
|
struct drm_device *dev = &dev_priv->drm;
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
|
|
|
|
|
struct drm_atomic_state *state;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2017-07-19 14:54:55 +02:00
|
|
|
|
|
|
|
|
/* reset doesn't touch the display */
|
2017-09-19 19:38:44 +00:00
|
|
|
if (!i915_modparams.force_reset_modeset_test &&
|
2017-07-19 14:54:55 +02:00
|
|
|
!gpu_reset_clobbers_display(dev_priv))
|
|
|
|
|
return;
|
|
|
|
|
|
drm/i915: More surgically unbreak the modeset vs reset deadlock
There's no reason to entirely wedge the gpu, for the minimal deadlock
bugfix we only need to unbreak/decouple the atomic commit from the gpu
reset. The simplest way to fix that is by replacing the
unconditional fence wait a the top of commit_tail by a wait which
completes either when the fences are done (normal case, or when a
reset doesn't need to touch the display state). Or when the gpu reset
needs to force-unblock all pending modeset states.
The lesser source of deadlocks is when we try to pin a new framebuffer
and run into a stall. There's a bunch of places this can happen, like
eviction, changing the caching mode, acquiring a fence on older
platforms. And we can't just break the depency loop and keep going,
the only way would be to break out and restart. But the problem with
that approach is that we must stall for the reset to complete before
we grab any locks, and with the atomic infrastructure that's a bit
tricky. The only place is the ioctl code, and we don't want to insert
code into e.g. the BUSY ioctl. Hence for that problem just create a
critical section, and if any code is in there, wedge the GPU. For the
steady-state this should never be a problem.
Note that in both cases TDR itself keeps working, so from a userspace
pov this trickery isn't observable. Users themselvs might spot a short
glitch while the rendering is catching up again, but that's still
better than pre-TDR where we've thrown away all the rendering,
including innocent batches. Also, this fixes the regression TDR
introduced of making gpu resets deadlock-prone when we do need to
touch the display.
One thing I noticed is that gpu_error.flags seems to use both our own
wait-queue in gpu_error.wait_queue, and the generic wait_on_bit
facilities. Not entirely sure why this inconsistency exists, I just
picked one style.
A possible future avenue could be to insert the gpu reset in-between
ongoing modeset changes, which would avoid the momentary glitch. But
that's a lot more work to implement in the atomic commit machinery,
and given that we only need this for pre-g4x hw, of questionable
utility just for the sake of polishing gpu reset even more on those
old boxes. It might be useful for other features though.
v2: Rebase onto 4.13 with a s/wait_queue_t/struct wait_queue_entry/.
v3: Really emabarrassing fixup, I checked the wrong bit and broke the
unbreak/wakeup logic.
v4: Also handle deadlocks in pin_to_display.
v5: Review from Michel:
- Fixup the BUILD_BUG_ON
- Don't forget about the overlay
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v2)
Cc: Michel Thierry <michel.thierry@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170808080828.23650-3-daniel.vetter@ffwll.ch
Reviewed-by: Michel Thierry <michel.thierry@intel.com>
2017-08-08 10:08:28 +02:00
|
|
|
/* We have a modeset vs reset deadlock, defensively unbreak it. */
|
|
|
|
|
set_bit(I915_RESET_MODESET, &dev_priv->gpu_error.flags);
|
|
|
|
|
wake_up_all(&dev_priv->gpu_error.wait_queue);
|
|
|
|
|
|
|
|
|
|
if (atomic_read(&dev_priv->gpu_error.pending_fb_pin)) {
|
|
|
|
|
DRM_DEBUG_KMS("Modeset potentially stuck, unbreaking through wedging\n");
|
|
|
|
|
i915_gem_set_wedged(dev_priv);
|
|
|
|
|
}
|
2017-08-08 10:08:26 +02:00
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
/*
|
|
|
|
|
* Need mode_config.mutex so that we don't
|
|
|
|
|
* trample ongoing ->detect() and whatnot.
|
|
|
|
|
*/
|
|
|
|
|
mutex_lock(&dev->mode_config.mutex);
|
|
|
|
|
drm_modeset_acquire_init(ctx, 0);
|
|
|
|
|
while (1) {
|
|
|
|
|
ret = drm_modeset_lock_all_ctx(dev, ctx);
|
|
|
|
|
if (ret != -EDEADLK)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
drm_modeset_backoff(ctx);
|
|
|
|
|
}
|
2014-11-21 21:54:30 +02:00
|
|
|
/*
|
|
|
|
|
* Disabling the crtcs gracefully seems nicer. Also the
|
|
|
|
|
* g33 docs say we should at least disable all the planes.
|
|
|
|
|
*/
|
2016-08-05 23:28:27 +03:00
|
|
|
state = drm_atomic_helper_duplicate_state(dev, ctx);
|
|
|
|
|
if (IS_ERR(state)) {
|
|
|
|
|
ret = PTR_ERR(state);
|
|
|
|
|
DRM_ERROR("Duplicating state failed with %i\n", ret);
|
2017-01-18 14:34:28 +02:00
|
|
|
return;
|
2016-08-05 23:28:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = drm_atomic_helper_disable_all(dev, ctx);
|
|
|
|
|
if (ret) {
|
|
|
|
|
DRM_ERROR("Suspending crtc's failed with %i\n", ret);
|
2017-01-18 14:34:28 +02:00
|
|
|
drm_atomic_state_put(state);
|
|
|
|
|
return;
|
2016-08-05 23:28:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_priv->modeset_restore_state = state;
|
|
|
|
|
state->acquire_ctx = ctx;
|
2014-11-24 18:28:11 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-06 15:40:21 +01:00
|
|
|
void intel_finish_reset(struct drm_i915_private *dev_priv)
|
2014-11-24 18:28:11 +02:00
|
|
|
{
|
2016-08-05 23:28:27 +03:00
|
|
|
struct drm_device *dev = &dev_priv->drm;
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx;
|
|
|
|
|
struct drm_atomic_state *state = dev_priv->modeset_restore_state;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2017-07-19 14:54:55 +02:00
|
|
|
/* reset doesn't touch the display */
|
2017-09-19 19:38:44 +00:00
|
|
|
if (!i915_modparams.force_reset_modeset_test &&
|
2017-07-19 14:54:55 +02:00
|
|
|
!gpu_reset_clobbers_display(dev_priv))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!state)
|
|
|
|
|
goto unlock;
|
|
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
dev_priv->modeset_restore_state = NULL;
|
|
|
|
|
|
2014-11-24 18:28:11 +02:00
|
|
|
/* reset doesn't touch the display */
|
2016-08-05 23:28:29 +03:00
|
|
|
if (!gpu_reset_clobbers_display(dev_priv)) {
|
2017-07-19 14:54:55 +02:00
|
|
|
/* for testing only restore the display */
|
|
|
|
|
ret = __intel_display_resume(dev, state, ctx);
|
2017-08-28 11:46:04 +01:00
|
|
|
if (ret)
|
|
|
|
|
DRM_ERROR("Restoring old state failed with %i\n", ret);
|
2016-08-05 23:28:27 +03:00
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* The display has been reset as well,
|
|
|
|
|
* so need a full re-initialization.
|
|
|
|
|
*/
|
|
|
|
|
intel_runtime_pm_disable_interrupts(dev_priv);
|
|
|
|
|
intel_runtime_pm_enable_interrupts(dev_priv);
|
2014-11-24 18:28:11 +02:00
|
|
|
|
2016-09-14 13:04:13 +03:00
|
|
|
intel_pps_unlock_regs_wa(dev_priv);
|
2016-08-05 23:28:27 +03:00
|
|
|
intel_modeset_init_hw(dev);
|
2017-11-08 15:35:55 +02:00
|
|
|
intel_init_clock_gating(dev_priv);
|
2014-11-24 18:28:11 +02:00
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
spin_lock_irq(&dev_priv->irq_lock);
|
|
|
|
|
if (dev_priv->display.hpd_irq_setup)
|
|
|
|
|
dev_priv->display.hpd_irq_setup(dev_priv);
|
|
|
|
|
spin_unlock_irq(&dev_priv->irq_lock);
|
2014-11-24 18:28:11 +02:00
|
|
|
|
2017-01-16 10:37:38 +01:00
|
|
|
ret = __intel_display_resume(dev, state, ctx);
|
2016-08-05 23:28:27 +03:00
|
|
|
if (ret)
|
|
|
|
|
DRM_ERROR("Restoring old state failed with %i\n", ret);
|
2014-11-24 18:28:11 +02:00
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
intel_hpd_init(dev_priv);
|
|
|
|
|
}
|
2014-11-24 18:28:11 +02:00
|
|
|
|
2017-07-19 14:54:55 +02:00
|
|
|
drm_atomic_state_put(state);
|
|
|
|
|
unlock:
|
2016-08-05 23:28:27 +03:00
|
|
|
drm_modeset_drop_locks(ctx);
|
|
|
|
|
drm_modeset_acquire_fini(ctx);
|
|
|
|
|
mutex_unlock(&dev->mode_config.mutex);
|
drm/i915: More surgically unbreak the modeset vs reset deadlock
There's no reason to entirely wedge the gpu, for the minimal deadlock
bugfix we only need to unbreak/decouple the atomic commit from the gpu
reset. The simplest way to fix that is by replacing the
unconditional fence wait a the top of commit_tail by a wait which
completes either when the fences are done (normal case, or when a
reset doesn't need to touch the display state). Or when the gpu reset
needs to force-unblock all pending modeset states.
The lesser source of deadlocks is when we try to pin a new framebuffer
and run into a stall. There's a bunch of places this can happen, like
eviction, changing the caching mode, acquiring a fence on older
platforms. And we can't just break the depency loop and keep going,
the only way would be to break out and restart. But the problem with
that approach is that we must stall for the reset to complete before
we grab any locks, and with the atomic infrastructure that's a bit
tricky. The only place is the ioctl code, and we don't want to insert
code into e.g. the BUSY ioctl. Hence for that problem just create a
critical section, and if any code is in there, wedge the GPU. For the
steady-state this should never be a problem.
Note that in both cases TDR itself keeps working, so from a userspace
pov this trickery isn't observable. Users themselvs might spot a short
glitch while the rendering is catching up again, but that's still
better than pre-TDR where we've thrown away all the rendering,
including innocent batches. Also, this fixes the regression TDR
introduced of making gpu resets deadlock-prone when we do need to
touch the display.
One thing I noticed is that gpu_error.flags seems to use both our own
wait-queue in gpu_error.wait_queue, and the generic wait_on_bit
facilities. Not entirely sure why this inconsistency exists, I just
picked one style.
A possible future avenue could be to insert the gpu reset in-between
ongoing modeset changes, which would avoid the momentary glitch. But
that's a lot more work to implement in the atomic commit machinery,
and given that we only need this for pre-g4x hw, of questionable
utility just for the sake of polishing gpu reset even more on those
old boxes. It might be useful for other features though.
v2: Rebase onto 4.13 with a s/wait_queue_t/struct wait_queue_entry/.
v3: Really emabarrassing fixup, I checked the wrong bit and broke the
unbreak/wakeup logic.
v4: Also handle deadlocks in pin_to_display.
v5: Review from Michel:
- Fixup the BUILD_BUG_ON
- Don't forget about the overlay
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v2)
Cc: Michel Thierry <michel.thierry@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170808080828.23650-3-daniel.vetter@ffwll.ch
Reviewed-by: Michel Thierry <michel.thierry@intel.com>
2017-08-08 10:08:28 +02:00
|
|
|
|
|
|
|
|
clear_bit(I915_RESET_MODESET, &dev_priv->gpu_error.flags);
|
2014-11-24 18:28:11 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-23 18:22:25 +03:00
|
|
|
static void intel_update_pipe_config(const struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
const struct intel_crtc_state *new_crtc_state)
|
2014-09-10 12:04:17 -03:00
|
|
|
{
|
2017-08-23 18:22:25 +03:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2014-09-10 12:04:17 -03:00
|
|
|
|
2015-08-27 15:44:05 +02:00
|
|
|
/* drm_atomic_helper_update_legacy_modeset_state might not be called. */
|
2017-08-23 18:22:25 +03:00
|
|
|
crtc->base.mode = new_crtc_state->base.mode;
|
2015-08-27 15:44:05 +02:00
|
|
|
|
2014-09-10 12:04:17 -03:00
|
|
|
/*
|
|
|
|
|
* Update pipe size and adjust fitter if needed: the reason for this is
|
|
|
|
|
* that in compute_mode_changes we check the native mode (not the pfit
|
|
|
|
|
* mode) to see if we can flip rather than do a full mode set. In the
|
|
|
|
|
* fastboot case, we'll flip, but if we don't update the pipesrc and
|
|
|
|
|
* pfit state, we'll end up with a big fb scanned out into the wrong
|
|
|
|
|
* sized surface.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PIPESRC(crtc->pipe),
|
2017-08-23 18:22:25 +03:00
|
|
|
((new_crtc_state->pipe_src_w - 1) << 16) |
|
|
|
|
|
(new_crtc_state->pipe_src_h - 1));
|
2015-08-27 15:44:05 +02:00
|
|
|
|
|
|
|
|
/* on skylake this is done by detaching scalers */
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2015-08-27 15:44:05 +02:00
|
|
|
skl_detach_scalers(crtc);
|
|
|
|
|
|
2017-08-23 18:22:25 +03:00
|
|
|
if (new_crtc_state->pch_pfit.enabled)
|
2015-08-27 15:44:05 +02:00
|
|
|
skylake_pfit_enable(crtc);
|
2016-10-13 11:02:53 +01:00
|
|
|
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
2017-08-23 18:22:25 +03:00
|
|
|
if (new_crtc_state->pch_pfit.enabled)
|
2015-08-27 15:44:05 +02:00
|
|
|
ironlake_pfit_enable(crtc);
|
|
|
|
|
else if (old_crtc_state->pch_pfit.enabled)
|
|
|
|
|
ironlake_pfit_disable(crtc, true);
|
2014-09-10 12:04:17 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-02 14:58:51 +02:00
|
|
|
static void intel_fdi_normal_train(struct intel_crtc *crtc)
|
2010-10-28 16:38:08 +08:00
|
|
|
{
|
2017-03-02 14:58:51 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-03-02 14:58:51 +02:00
|
|
|
int pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp;
|
2010-10-28 16:38:08 +08:00
|
|
|
|
|
|
|
|
/* enable normal train */
|
|
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2016-10-14 10:13:06 +01:00
|
|
|
if (IS_IVYBRIDGE(dev_priv)) {
|
2011-04-28 15:09:55 -07:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE_IVB;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
|
2011-05-17 16:13:52 -07:00
|
|
|
} else {
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
|
2011-04-28 15:09:55 -07:00
|
|
|
}
|
2010-10-28 16:38:08 +08:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2010-10-28 16:38:08 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_NORMAL_CPT;
|
|
|
|
|
} else {
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_NONE;
|
|
|
|
|
}
|
|
|
|
|
I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
|
|
|
|
|
|
|
|
|
|
/* wait one idle pattern time */
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(1000);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
|
|
|
|
/* IVB wants error correction enabled */
|
2016-10-14 10:13:06 +01:00
|
|
|
if (IS_IVYBRIDGE(dev_priv))
|
2011-04-28 15:09:55 -07:00
|
|
|
I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE |
|
|
|
|
|
FDI_FE_ERRC_ENABLE);
|
2010-10-28 16:38:08 +08:00
|
|
|
}
|
|
|
|
|
|
2010-04-07 16:15:54 +08:00
|
|
|
/* The FDI link training functions for ILK/Ibexpeak. */
|
2017-03-02 14:58:54 +02:00
|
|
|
static void ironlake_fdi_link_train(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *crtc_state)
|
2010-04-07 16:15:54 +08:00
|
|
|
{
|
2017-03-02 14:58:51 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-03-02 14:58:51 +02:00
|
|
|
int pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp, tries;
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2014-04-25 22:12:07 +03:00
|
|
|
/* FDI needs bits from pipe first */
|
2011-01-04 15:09:37 -08:00
|
|
|
assert_pipe_enabled(dev_priv, pipe);
|
|
|
|
|
|
2010-06-25 15:32:14 -04:00
|
|
|
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
|
|
|
|
|
for train result */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_IMR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-06-25 15:32:14 -04:00
|
|
|
temp &= ~FDI_RX_SYMBOL_LOCK;
|
|
|
|
|
temp &= ~FDI_RX_BIT_LOCK;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
I915_READ(reg);
|
2010-06-25 15:32:14 -04:00
|
|
|
udelay(150);
|
|
|
|
|
|
2010-04-07 16:15:54 +08:00
|
|
|
/* enable CPU FDI TX and PCH FDI RX */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2013-04-29 19:33:42 +02:00
|
|
|
temp &= ~FDI_DP_PORT_WIDTH_MASK;
|
2017-03-02 14:58:54 +02:00
|
|
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_TX_ENABLE);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_RX_ENABLE);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
udelay(150);
|
|
|
|
|
|
2010-10-07 16:01:15 -07:00
|
|
|
/* Ironlake workaround, enable clock pointer after FDI enable*/
|
2012-10-31 22:52:28 +01:00
|
|
|
I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
|
|
|
|
|
I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR |
|
|
|
|
|
FDI_RX_PHASE_SYNC_POINTER_EN);
|
2010-10-07 16:01:15 -07:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_IIR(pipe);
|
2010-06-25 15:32:14 -04:00
|
|
|
for (tries = 0; tries < 5; tries++) {
|
2010-09-11 13:48:45 +01:00
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
|
|
|
|
|
|
|
|
|
|
if ((temp & FDI_RX_BIT_LOCK)) {
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 1 done.\n");
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
|
2010-04-07 16:15:54 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-25 15:32:14 -04:00
|
|
|
if (tries == 5)
|
2010-09-11 13:48:45 +01:00
|
|
|
DRM_ERROR("FDI train 1 fail!\n");
|
2010-04-07 16:15:54 +08:00
|
|
|
|
|
|
|
|
/* Train 2 */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(150);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_IIR(pipe);
|
2010-06-25 15:32:14 -04:00
|
|
|
for (tries = 0; tries < 5; tries++) {
|
2010-09-11 13:48:45 +01:00
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
|
|
|
|
|
|
|
|
|
|
if (temp & FDI_RX_SYMBOL_LOCK) {
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
|
2010-04-07 16:15:54 +08:00
|
|
|
DRM_DEBUG_KMS("FDI train 2 done.\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-25 15:32:14 -04:00
|
|
|
if (tries == 5)
|
2010-09-11 13:48:45 +01:00
|
|
|
DRM_ERROR("FDI train 2 fail!\n");
|
2010-04-07 16:15:54 +08:00
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("FDI train done\n");
|
2010-10-07 16:01:11 -07:00
|
|
|
|
2010-04-07 16:15:54 +08:00
|
|
|
}
|
|
|
|
|
|
2011-08-16 15:34:10 -04:00
|
|
|
static const int snb_b_fdi_train_param[] = {
|
2010-04-07 16:15:54 +08:00
|
|
|
FDI_LINK_TRAIN_400MV_0DB_SNB_B,
|
|
|
|
|
FDI_LINK_TRAIN_400MV_6DB_SNB_B,
|
|
|
|
|
FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
|
|
|
|
|
FDI_LINK_TRAIN_800MV_0DB_SNB_B,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* The FDI link training functions for SNB/Cougarpoint. */
|
2017-03-02 14:58:54 +02:00
|
|
|
static void gen6_fdi_link_train(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *crtc_state)
|
2010-04-07 16:15:54 +08:00
|
|
|
{
|
2017-03-02 14:58:51 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-03-02 14:58:51 +02:00
|
|
|
int pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp, i, retry;
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2010-06-25 15:32:14 -04:00
|
|
|
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
|
|
|
|
|
for train result */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_IMR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-06-25 15:32:14 -04:00
|
|
|
temp &= ~FDI_RX_SYMBOL_LOCK;
|
|
|
|
|
temp &= ~FDI_RX_BIT_LOCK;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-06-25 15:32:14 -04:00
|
|
|
udelay(150);
|
|
|
|
|
|
2010-04-07 16:15:54 +08:00
|
|
|
/* enable CPU FDI TX and PCH FDI RX */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2013-04-29 19:33:42 +02:00
|
|
|
temp &= ~FDI_DP_PORT_WIDTH_MASK;
|
2017-03-02 14:58:54 +02:00
|
|
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
|
|
|
|
/* SNB-B */
|
|
|
|
|
temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_TX_ENABLE);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2012-10-26 10:58:13 +02:00
|
|
|
I915_WRITE(FDI_RX_MISC(pipe),
|
|
|
|
|
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
|
|
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
|
|
|
|
|
} else {
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
|
|
|
|
}
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_RX_ENABLE);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
udelay(150);
|
|
|
|
|
|
2011-08-16 15:34:10 -04:00
|
|
|
for (i = 0; i < 4; i++) {
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
|
|
|
|
temp |= snb_b_fdi_train_param[i];
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
udelay(500);
|
|
|
|
|
|
2012-03-02 12:53:39 -05:00
|
|
|
for (retry = 0; retry < 5; retry++) {
|
|
|
|
|
reg = FDI_RX_IIR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
|
|
|
|
|
if (temp & FDI_RX_BIT_LOCK) {
|
|
|
|
|
I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 1 done.\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
udelay(50);
|
2010-04-07 16:15:54 +08:00
|
|
|
}
|
2012-03-02 12:53:39 -05:00
|
|
|
if (retry < 5)
|
|
|
|
|
break;
|
2010-04-07 16:15:54 +08:00
|
|
|
}
|
|
|
|
|
if (i == 4)
|
2010-09-11 13:48:45 +01:00
|
|
|
DRM_ERROR("FDI train 1 fail!\n");
|
2010-04-07 16:15:54 +08:00
|
|
|
|
|
|
|
|
/* Train 2 */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN6(dev_priv)) {
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
|
|
|
|
/* SNB-B */
|
|
|
|
|
temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
|
|
|
|
|
}
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
|
|
|
|
|
} else {
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
|
|
|
|
}
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
udelay(150);
|
|
|
|
|
|
2011-08-16 15:34:10 -04:00
|
|
|
for (i = 0; i < 4; i++) {
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
|
|
|
|
temp |= snb_b_fdi_train_param[i];
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-04-07 16:15:54 +08:00
|
|
|
udelay(500);
|
|
|
|
|
|
2012-03-02 12:53:39 -05:00
|
|
|
for (retry = 0; retry < 5; retry++) {
|
|
|
|
|
reg = FDI_RX_IIR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
|
|
|
|
|
if (temp & FDI_RX_SYMBOL_LOCK) {
|
|
|
|
|
I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 2 done.\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
udelay(50);
|
2010-04-07 16:15:54 +08:00
|
|
|
}
|
2012-03-02 12:53:39 -05:00
|
|
|
if (retry < 5)
|
|
|
|
|
break;
|
2010-04-07 16:15:54 +08:00
|
|
|
}
|
|
|
|
|
if (i == 4)
|
2010-09-11 13:48:45 +01:00
|
|
|
DRM_ERROR("FDI train 2 fail!\n");
|
2010-04-07 16:15:54 +08:00
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("FDI train done.\n");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-28 15:09:55 -07:00
|
|
|
/* Manual link training for Ivy Bridge A0 parts */
|
2017-03-02 14:58:54 +02:00
|
|
|
static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *crtc_state)
|
2011-04-28 15:09:55 -07:00
|
|
|
{
|
2017-03-02 14:58:51 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-03-02 14:58:51 +02:00
|
|
|
int pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp, i, j;
|
2011-04-28 15:09:55 -07:00
|
|
|
|
|
|
|
|
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
|
|
|
|
|
for train result */
|
|
|
|
|
reg = FDI_RX_IMR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~FDI_RX_SYMBOL_LOCK;
|
|
|
|
|
temp &= ~FDI_RX_BIT_LOCK;
|
|
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(150);
|
|
|
|
|
|
2012-10-27 15:58:40 +02:00
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR before link train 0x%x\n",
|
|
|
|
|
I915_READ(FDI_RX_IIR(pipe)));
|
|
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
/* Try each vswing and preemphasis setting twice before moving on */
|
|
|
|
|
for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
|
|
|
|
|
/* disable first in case we need to retry */
|
|
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
|
|
|
|
|
temp &= ~FDI_TX_ENABLE;
|
|
|
|
|
I915_WRITE(reg, temp);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_AUTO;
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
|
|
|
|
temp &= ~FDI_RX_ENABLE;
|
|
|
|
|
I915_WRITE(reg, temp);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
/* enable CPU FDI TX and PCH FDI RX */
|
2011-04-28 15:09:55 -07:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2013-08-19 11:04:55 -07:00
|
|
|
temp &= ~FDI_DP_PORT_WIDTH_MASK;
|
2017-03-02 14:58:54 +02:00
|
|
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
2013-08-19 11:04:55 -07:00
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
|
2011-04-28 15:09:55 -07:00
|
|
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
2013-08-19 11:04:55 -07:00
|
|
|
temp |= snb_b_fdi_train_param[j/2];
|
|
|
|
|
temp |= FDI_COMPOSITE_SYNC;
|
|
|
|
|
I915_WRITE(reg, temp | FDI_TX_ENABLE);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
I915_WRITE(FDI_RX_MISC(pipe),
|
|
|
|
|
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
2011-04-28 15:09:55 -07:00
|
|
|
temp = I915_READ(reg);
|
2013-08-19 11:04:55 -07:00
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
|
|
|
|
|
temp |= FDI_COMPOSITE_SYNC;
|
|
|
|
|
I915_WRITE(reg, temp | FDI_RX_ENABLE);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(1); /* should be 0.5us */
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
|
reg = FDI_RX_IIR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
if (temp & FDI_RX_BIT_LOCK ||
|
|
|
|
|
(I915_READ(reg) & FDI_RX_BIT_LOCK)) {
|
|
|
|
|
I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 1 done, level %i.\n",
|
|
|
|
|
i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
udelay(1); /* should be 0.5us */
|
|
|
|
|
}
|
|
|
|
|
if (i == 4) {
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 1 fail on vswing %d\n", j / 2);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
/* Train 2 */
|
2011-04-28 15:09:55 -07:00
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2013-08-19 11:04:55 -07:00
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE_IVB;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
|
|
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
|
2011-04-28 15:09:55 -07:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2013-08-19 11:04:55 -07:00
|
|
|
udelay(2); /* should be 1.5us */
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
|
reg = FDI_RX_IIR(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
|
2011-04-28 15:09:55 -07:00
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
if (temp & FDI_RX_SYMBOL_LOCK ||
|
|
|
|
|
(I915_READ(reg) & FDI_RX_SYMBOL_LOCK)) {
|
|
|
|
|
I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 2 done, level %i.\n",
|
|
|
|
|
i);
|
|
|
|
|
goto train_done;
|
|
|
|
|
}
|
|
|
|
|
udelay(2); /* should be 1.5us */
|
2011-04-28 15:09:55 -07:00
|
|
|
}
|
2013-08-19 11:04:55 -07:00
|
|
|
if (i == 4)
|
|
|
|
|
DRM_DEBUG_KMS("FDI train 2 fail on vswing %d\n", j / 2);
|
2011-04-28 15:09:55 -07:00
|
|
|
}
|
|
|
|
|
|
2013-08-19 11:04:55 -07:00
|
|
|
train_done:
|
2011-04-28 15:09:55 -07:00
|
|
|
DRM_DEBUG_KMS("FDI train done.\n");
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-12 19:27:14 +02:00
|
|
|
static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
|
2009-06-05 15:38:42 +08:00
|
|
|
{
|
2012-08-12 19:27:14 +02:00
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2009-06-05 15:38:42 +08:00
|
|
|
int pipe = intel_crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp;
|
2010-09-10 11:27:03 -07:00
|
|
|
|
2010-09-10 10:57:18 -07:00
|
|
|
/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
|
2010-09-11 13:48:45 +01:00
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2013-04-29 19:33:42 +02:00
|
|
|
temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
|
2015-01-15 14:55:25 +02:00
|
|
|
temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
|
2012-12-17 11:21:38 +01:00
|
|
|
temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-09-10 10:57:18 -07:00
|
|
|
udelay(200);
|
|
|
|
|
|
|
|
|
|
/* Switch from Rawclk to PCDclk */
|
2010-09-11 13:48:45 +01:00
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
I915_WRITE(reg, temp | FDI_PCDCLK);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
2010-09-10 10:57:18 -07:00
|
|
|
udelay(200);
|
|
|
|
|
|
2012-11-23 15:30:38 -02:00
|
|
|
/* Enable CPU FDI TX PLL, always on for Ironlake */
|
|
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
if ((temp & FDI_TX_PLL_ENABLE) == 0) {
|
|
|
|
|
I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
|
2010-09-11 13:48:45 +01:00
|
|
|
|
2012-11-23 15:30:38 -02:00
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(100);
|
2010-09-10 10:26:01 -07:00
|
|
|
}
|
2010-09-10 11:10:00 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-12 19:27:14 +02:00
|
|
|
static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2012-08-12 19:27:14 +02:00
|
|
|
int pipe = intel_crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp;
|
2012-08-12 19:27:14 +02:00
|
|
|
|
|
|
|
|
/* Switch from PCDclk to Rawclk */
|
|
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
I915_WRITE(reg, temp & ~FDI_PCDCLK);
|
|
|
|
|
|
|
|
|
|
/* Disable CPU FDI TX PLL */
|
|
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(100);
|
|
|
|
|
|
|
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
|
|
|
|
|
|
|
|
|
|
/* Wait for the clocks to turn off. */
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(100);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-04 15:09:37 -08:00
|
|
|
static void ironlake_fdi_disable(struct drm_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2011-01-04 15:09:37 -08:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp;
|
2011-01-04 15:09:37 -08:00
|
|
|
|
|
|
|
|
/* disable CPU FDI tx and PCH FDI rx */
|
|
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
|
|
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~(0x7 << 16);
|
2012-12-17 11:21:38 +01:00
|
|
|
temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
|
2011-01-04 15:09:37 -08:00
|
|
|
I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(100);
|
|
|
|
|
|
|
|
|
|
/* Ironlake workaround, disable clock pointer after downing FDI */
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_IBX(dev_priv))
|
2011-01-04 15:09:38 -08:00
|
|
|
I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
|
2011-01-04 15:09:37 -08:00
|
|
|
|
|
|
|
|
/* still set train pattern 1 */
|
|
|
|
|
reg = FDI_TX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
|
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
reg = FDI_RX_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2011-01-04 15:09:37 -08:00
|
|
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
|
|
|
|
|
} else {
|
|
|
|
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
|
|
|
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
|
|
|
|
}
|
|
|
|
|
/* BPC in FDI rx is consistent with that in PIPECONF */
|
|
|
|
|
temp &= ~(0x07 << 16);
|
2012-12-17 11:21:38 +01:00
|
|
|
temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
|
2011-01-04 15:09:37 -08:00
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
POSTING_READ(reg);
|
|
|
|
|
udelay(100);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-29 09:50:08 +00:00
|
|
|
bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv)
|
2014-01-20 10:17:36 +00:00
|
|
|
{
|
2017-07-20 19:57:52 +02:00
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
bool cleanup_done;
|
|
|
|
|
|
|
|
|
|
drm_for_each_crtc(crtc, &dev_priv->drm) {
|
|
|
|
|
struct drm_crtc_commit *commit;
|
|
|
|
|
spin_lock(&crtc->commit_lock);
|
|
|
|
|
commit = list_first_entry_or_null(&crtc->commit_list,
|
|
|
|
|
struct drm_crtc_commit, commit_entry);
|
|
|
|
|
cleanup_done = commit ?
|
|
|
|
|
try_wait_for_completion(&commit->cleanup_done) : true;
|
|
|
|
|
spin_unlock(&crtc->commit_lock);
|
|
|
|
|
|
|
|
|
|
if (cleanup_done)
|
2014-01-20 10:17:36 +00:00
|
|
|
continue;
|
|
|
|
|
|
2017-07-20 19:57:52 +02:00
|
|
|
drm_crtc_wait_one_vblank(crtc);
|
2014-01-20 10:17:36 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-23 16:18:08 +02:00
|
|
|
void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
|
2015-12-04 22:21:34 +02:00
|
|
|
{
|
|
|
|
|
u32 temp;
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
|
|
|
|
|
|
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
|
|
|
|
|
temp |= SBI_SSCCTL_DISABLE;
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-09 15:37:26 -03:00
|
|
|
/* Program iCLKIP clock to the desired frequency */
|
2017-03-02 14:58:52 +02:00
|
|
|
static void lpt_program_iclkip(struct intel_crtc *crtc)
|
2012-05-09 15:37:26 -03:00
|
|
|
{
|
2017-03-02 14:58:52 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
int clock = crtc->config->base.adjusted_mode.crtc_clock;
|
2012-05-09 15:37:26 -03:00
|
|
|
u32 divsel, phaseinc, auxdiv, phasedir = 0;
|
|
|
|
|
u32 temp;
|
|
|
|
|
|
2015-12-04 22:21:34 +02:00
|
|
|
lpt_disable_iclkip(dev_priv);
|
2012-05-09 15:37:26 -03:00
|
|
|
|
2016-02-17 21:41:11 +02:00
|
|
|
/* The iCLK virtual clock root frequency is in MHz,
|
|
|
|
|
* but the adjusted_mode->crtc_clock in in KHz. To get the
|
|
|
|
|
* divisors, it is necessary to divide one by another, so we
|
|
|
|
|
* convert the virtual clock precision to KHz here for higher
|
|
|
|
|
* precision.
|
|
|
|
|
*/
|
|
|
|
|
for (auxdiv = 0; auxdiv < 2; auxdiv++) {
|
2012-05-09 15:37:26 -03:00
|
|
|
u32 iclk_virtual_root_freq = 172800 * 1000;
|
|
|
|
|
u32 iclk_pi_range = 64;
|
2016-02-17 21:41:11 +02:00
|
|
|
u32 desired_divisor;
|
2012-05-09 15:37:26 -03:00
|
|
|
|
2016-02-17 21:41:11 +02:00
|
|
|
desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
|
|
|
|
|
clock << auxdiv);
|
|
|
|
|
divsel = (desired_divisor / iclk_pi_range) - 2;
|
|
|
|
|
phaseinc = desired_divisor % iclk_pi_range;
|
2012-05-09 15:37:26 -03:00
|
|
|
|
2016-02-17 21:41:11 +02:00
|
|
|
/*
|
|
|
|
|
* Near 20MHz is a corner case which is
|
|
|
|
|
* out of range for the 7-bit divisor
|
|
|
|
|
*/
|
|
|
|
|
if (divsel <= 0x7f)
|
|
|
|
|
break;
|
2012-05-09 15:37:26 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This should not happen with any sane values */
|
|
|
|
|
WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) &
|
|
|
|
|
~SBI_SSCDIVINTPHASE_DIVSEL_MASK);
|
|
|
|
|
WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) &
|
|
|
|
|
~SBI_SSCDIVINTPHASE_INCVAL_MASK);
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
|
2013-09-04 18:25:19 +03:00
|
|
|
clock,
|
2012-05-09 15:37:26 -03:00
|
|
|
auxdiv,
|
|
|
|
|
divsel,
|
|
|
|
|
phasedir,
|
|
|
|
|
phaseinc);
|
|
|
|
|
|
2015-12-04 22:21:34 +02:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
|
|
|
|
|
2012-05-09 15:37:26 -03:00
|
|
|
/* Program SSCDIVINTPHASE6 */
|
2012-12-01 12:04:24 -02:00
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
|
2012-05-09 15:37:26 -03:00
|
|
|
temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
|
|
|
|
|
temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel);
|
|
|
|
|
temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;
|
|
|
|
|
temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc);
|
|
|
|
|
temp |= SBI_SSCDIVINTPHASE_DIR(phasedir);
|
|
|
|
|
temp |= SBI_SSCDIVINTPHASE_PROPAGATE;
|
2012-12-01 12:04:24 -02:00
|
|
|
intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK);
|
2012-05-09 15:37:26 -03:00
|
|
|
|
|
|
|
|
/* Program SSCAUXDIV */
|
2012-12-01 12:04:24 -02:00
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
|
2012-05-09 15:37:26 -03:00
|
|
|
temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);
|
|
|
|
|
temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv);
|
2012-12-01 12:04:24 -02:00
|
|
|
intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK);
|
2012-05-09 15:37:26 -03:00
|
|
|
|
|
|
|
|
/* Enable modulator and associated divider */
|
2012-12-01 12:04:24 -02:00
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
|
2012-05-09 15:37:26 -03:00
|
|
|
temp &= ~SBI_SSCCTL_DISABLE;
|
2012-12-01 12:04:24 -02:00
|
|
|
intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
|
2012-05-09 15:37:26 -03:00
|
|
|
|
2015-12-04 22:21:34 +02:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
|
|
|
|
|
2012-05-09 15:37:26 -03:00
|
|
|
/* Wait for initialization time */
|
|
|
|
|
udelay(24);
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 21:41:12 +02:00
|
|
|
int lpt_get_iclkip(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
u32 divsel, phaseinc, auxdiv;
|
|
|
|
|
u32 iclk_virtual_root_freq = 172800 * 1000;
|
|
|
|
|
u32 iclk_pi_range = 64;
|
|
|
|
|
u32 desired_divisor;
|
|
|
|
|
u32 temp;
|
|
|
|
|
|
|
|
|
|
if ((I915_READ(PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
|
|
|
|
|
|
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
|
|
|
|
|
if (temp & SBI_SSCCTL_DISABLE) {
|
|
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
|
|
|
|
|
divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
|
|
|
|
|
SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
|
|
|
|
|
phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
|
|
|
|
|
SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
|
|
|
|
|
|
|
|
|
|
temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
|
|
|
|
|
auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
|
|
|
|
|
SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
|
|
|
|
|
|
|
|
|
desired_divisor = (divsel + 2) * iclk_pi_range + phaseinc;
|
|
|
|
|
|
|
|
|
|
return DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
|
|
|
|
|
desired_divisor << auxdiv);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-03 11:49:47 +02:00
|
|
|
static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
|
|
|
|
|
enum pipe pch_transcoder)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-01-15 14:55:25 +02:00
|
|
|
enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
|
2013-05-03 11:49:47 +02:00
|
|
|
|
|
|
|
|
I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
|
|
|
|
|
I915_READ(HTOTAL(cpu_transcoder)));
|
|
|
|
|
I915_WRITE(PCH_TRANS_HBLANK(pch_transcoder),
|
|
|
|
|
I915_READ(HBLANK(cpu_transcoder)));
|
|
|
|
|
I915_WRITE(PCH_TRANS_HSYNC(pch_transcoder),
|
|
|
|
|
I915_READ(HSYNC(cpu_transcoder)));
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PCH_TRANS_VTOTAL(pch_transcoder),
|
|
|
|
|
I915_READ(VTOTAL(cpu_transcoder)));
|
|
|
|
|
I915_WRITE(PCH_TRANS_VBLANK(pch_transcoder),
|
|
|
|
|
I915_READ(VBLANK(cpu_transcoder)));
|
|
|
|
|
I915_WRITE(PCH_TRANS_VSYNC(pch_transcoder),
|
|
|
|
|
I915_READ(VSYNC(cpu_transcoder)));
|
|
|
|
|
I915_WRITE(PCH_TRANS_VSYNCSHIFT(pch_transcoder),
|
|
|
|
|
I915_READ(VSYNCSHIFT(cpu_transcoder)));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-11 13:35:43 +02:00
|
|
|
static void cpt_set_fdi_bc_bifurcation(struct drm_device *dev, bool enable)
|
2013-10-29 12:04:08 +01:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-10-29 12:04:08 +01:00
|
|
|
uint32_t temp;
|
|
|
|
|
|
|
|
|
|
temp = I915_READ(SOUTH_CHICKEN1);
|
2015-03-11 13:35:43 +02:00
|
|
|
if (!!(temp & FDI_BC_BIFURCATION_SELECT) == enable)
|
2013-10-29 12:04:08 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE);
|
|
|
|
|
WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE);
|
|
|
|
|
|
2015-03-11 13:35:43 +02:00
|
|
|
temp &= ~FDI_BC_BIFURCATION_SELECT;
|
|
|
|
|
if (enable)
|
|
|
|
|
temp |= FDI_BC_BIFURCATION_SELECT;
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("%sabling fdi C rx\n", enable ? "en" : "dis");
|
2013-10-29 12:04:08 +01:00
|
|
|
I915_WRITE(SOUTH_CHICKEN1, temp);
|
|
|
|
|
POSTING_READ(SOUTH_CHICKEN1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
|
|
|
|
|
|
|
|
|
switch (intel_crtc->pipe) {
|
|
|
|
|
case PIPE_A:
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_B:
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->fdi_lanes > 2)
|
2015-03-11 13:35:43 +02:00
|
|
|
cpt_set_fdi_bc_bifurcation(dev, false);
|
2013-10-29 12:04:08 +01:00
|
|
|
else
|
2015-03-11 13:35:43 +02:00
|
|
|
cpt_set_fdi_bc_bifurcation(dev, true);
|
2013-10-29 12:04:08 +01:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_C:
|
2015-03-11 13:35:43 +02:00
|
|
|
cpt_set_fdi_bc_bifurcation(dev, true);
|
2013-10-29 12:04:08 +01:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BUG();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-04 23:19:56 +02:00
|
|
|
/* Return which DP Port should be selected for Transcoder DP control */
|
|
|
|
|
static enum port
|
2017-03-02 14:58:51 +02:00
|
|
|
intel_trans_dp_port_sel(struct intel_crtc *crtc)
|
2015-11-04 23:19:56 +02:00
|
|
|
{
|
2017-03-02 14:58:51 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2015-11-04 23:19:56 +02:00
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
|
2017-03-02 14:58:51 +02:00
|
|
|
for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
|
2016-06-22 21:57:06 +03:00
|
|
|
if (encoder->type == INTEL_OUTPUT_DP ||
|
2015-11-04 23:19:56 +02:00
|
|
|
encoder->type == INTEL_OUTPUT_EDP)
|
2017-11-09 17:24:34 +02:00
|
|
|
return encoder->port;
|
2015-11-04 23:19:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-05 10:31:48 -08:00
|
|
|
/*
|
|
|
|
|
* Enable PCH resources required for PCH ports:
|
|
|
|
|
* - PCH PLLs
|
|
|
|
|
* - FDI training & RX/TX
|
|
|
|
|
* - update transcoder timings
|
|
|
|
|
* - DP transcoding bits
|
|
|
|
|
* - transcoder
|
|
|
|
|
*/
|
2017-03-02 14:58:53 +02:00
|
|
|
static void ironlake_pch_enable(const struct intel_crtc_state *crtc_state)
|
2010-09-10 11:10:00 -07:00
|
|
|
{
|
2017-03-02 14:58:53 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
2017-03-02 14:58:51 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-03-02 14:58:51 +02:00
|
|
|
int pipe = crtc->pipe;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
u32 temp;
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2013-05-03 11:49:46 +02:00
|
|
|
assert_pch_transcoder_disabled(dev_priv, pipe);
|
2012-05-11 09:21:25 +01:00
|
|
|
|
2016-10-14 10:13:06 +01:00
|
|
|
if (IS_IVYBRIDGE(dev_priv))
|
2017-03-02 14:58:51 +02:00
|
|
|
ivybridge_update_fdi_bc_bifurcation(crtc);
|
2013-10-29 12:04:08 +01:00
|
|
|
|
2012-10-26 10:58:12 +02:00
|
|
|
/* Write the TU size bits before fdi link training, so that error
|
|
|
|
|
* detection works. */
|
|
|
|
|
I915_WRITE(FDI_RX_TUSIZE1(pipe),
|
|
|
|
|
I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
|
|
|
|
|
|
2010-09-10 10:57:18 -07:00
|
|
|
/* For PCH output, training FDI link */
|
2017-03-02 14:58:54 +02:00
|
|
|
dev_priv->display.fdi_link_train(crtc, crtc_state);
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2013-06-05 13:34:32 +02:00
|
|
|
/* We need to program the right clock selection before writing the pixel
|
|
|
|
|
* mutliplier into the DPLL. */
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
2012-04-20 17:11:53 +01:00
|
|
|
u32 sel;
|
2011-10-12 09:51:31 -07:00
|
|
|
|
2010-09-10 10:57:18 -07:00
|
|
|
temp = I915_READ(PCH_DPLL_SEL);
|
2013-06-05 13:34:09 +02:00
|
|
|
temp |= TRANS_DPLL_ENABLE(pipe);
|
|
|
|
|
sel = TRANS_DPLLB_SEL(pipe);
|
2017-03-02 14:58:53 +02:00
|
|
|
if (crtc_state->shared_dpll ==
|
2016-03-08 17:46:18 +02:00
|
|
|
intel_get_shared_dpll_by_id(dev_priv, DPLL_ID_PCH_PLL_B))
|
2012-04-20 17:11:53 +01:00
|
|
|
temp |= sel;
|
|
|
|
|
else
|
|
|
|
|
temp &= ~sel;
|
2010-09-10 10:57:18 -07:00
|
|
|
I915_WRITE(PCH_DPLL_SEL, temp);
|
|
|
|
|
}
|
2010-09-11 13:48:45 +01:00
|
|
|
|
2013-06-05 13:34:32 +02:00
|
|
|
/* XXX: pch pll's can be enabled any time before we enable the PCH
|
|
|
|
|
* transcoder, and we actually should do this to not upset any PCH
|
|
|
|
|
* transcoder that already use the clock when we share it.
|
|
|
|
|
*
|
|
|
|
|
* Note that enable_shared_dpll tries to do the right thing, but
|
|
|
|
|
* get_shared_dpll unconditionally resets the pll - we need that to have
|
|
|
|
|
* the right LVDS enable sequence. */
|
2017-03-02 14:58:51 +02:00
|
|
|
intel_enable_shared_dpll(crtc);
|
2013-06-05 13:34:32 +02:00
|
|
|
|
2011-01-04 15:09:35 -08:00
|
|
|
/* set transcoder timing, panel must allow it */
|
|
|
|
|
assert_panel_unlocked(dev_priv, pipe);
|
2017-03-02 14:58:51 +02:00
|
|
|
ironlake_pch_transcoder_set_timings(crtc, pipe);
|
2010-04-07 16:15:54 +08:00
|
|
|
|
2012-10-31 18:12:23 -02:00
|
|
|
intel_fdi_normal_train(crtc);
|
2010-10-28 16:38:08 +08:00
|
|
|
|
2010-09-10 10:57:18 -07:00
|
|
|
/* For PCH DP, enable TRANS_DP_CTL */
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv) &&
|
2017-03-02 14:58:53 +02:00
|
|
|
intel_crtc_has_dp_encoder(crtc_state)) {
|
2015-10-29 21:25:51 +02:00
|
|
|
const struct drm_display_mode *adjusted_mode =
|
2017-03-02 14:58:53 +02:00
|
|
|
&crtc_state->base.adjusted_mode;
|
2012-12-17 11:21:38 +01:00
|
|
|
u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5;
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg = TRANS_DP_CTL(pipe);
|
2010-09-11 13:48:45 +01:00
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~(TRANS_DP_PORT_SEL_MASK |
|
2010-11-18 09:32:58 +08:00
|
|
|
TRANS_DP_SYNC_MASK |
|
|
|
|
|
TRANS_DP_BPC_MASK);
|
2015-05-05 17:17:31 +03:00
|
|
|
temp |= TRANS_DP_OUTPUT_ENABLE;
|
2011-06-24 12:19:21 -07:00
|
|
|
temp |= bpc << 9; /* same format but at 11:9 */
|
2010-09-10 10:57:18 -07:00
|
|
|
|
2015-10-29 21:25:51 +02:00
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
2010-09-11 13:48:45 +01:00
|
|
|
temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
|
2015-10-29 21:25:51 +02:00
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
2010-09-11 13:48:45 +01:00
|
|
|
temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
|
2010-09-10 10:57:18 -07:00
|
|
|
|
|
|
|
|
switch (intel_trans_dp_port_sel(crtc)) {
|
2015-11-04 23:19:56 +02:00
|
|
|
case PORT_B:
|
2010-09-11 13:48:45 +01:00
|
|
|
temp |= TRANS_DP_PORT_SEL_B;
|
2010-09-10 10:57:18 -07:00
|
|
|
break;
|
2015-11-04 23:19:56 +02:00
|
|
|
case PORT_C:
|
2010-09-11 13:48:45 +01:00
|
|
|
temp |= TRANS_DP_PORT_SEL_C;
|
2010-09-10 10:57:18 -07:00
|
|
|
break;
|
2015-11-04 23:19:56 +02:00
|
|
|
case PORT_D:
|
2010-09-11 13:48:45 +01:00
|
|
|
temp |= TRANS_DP_PORT_SEL_D;
|
2010-09-10 10:57:18 -07:00
|
|
|
break;
|
|
|
|
|
default:
|
2012-10-26 10:58:16 +02:00
|
|
|
BUG();
|
2009-07-24 01:00:32 +08:00
|
|
|
}
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
I915_WRITE(reg, temp);
|
2010-09-10 10:26:01 -07:00
|
|
|
}
|
2010-06-12 14:32:27 +08:00
|
|
|
|
2012-10-31 18:12:42 -02:00
|
|
|
ironlake_enable_pch_transcoder(dev_priv, pipe);
|
2011-01-05 10:31:48 -08:00
|
|
|
}
|
|
|
|
|
|
2017-03-02 14:58:53 +02:00
|
|
|
static void lpt_pch_enable(const struct intel_crtc_state *crtc_state)
|
2012-10-31 18:12:22 -02:00
|
|
|
{
|
2017-03-02 14:58:53 +02:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
2017-03-02 14:58:52 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2017-03-02 14:58:53 +02:00
|
|
|
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
2012-10-31 18:12:22 -02:00
|
|
|
|
2017-07-17 11:14:03 -07:00
|
|
|
assert_pch_transcoder_disabled(dev_priv, PIPE_A);
|
2012-10-31 18:12:22 -02:00
|
|
|
|
2012-10-31 18:12:24 -02:00
|
|
|
lpt_program_iclkip(crtc);
|
2012-10-31 18:12:22 -02:00
|
|
|
|
2012-10-31 18:12:40 -02:00
|
|
|
/* Set transcoder timing. */
|
2017-03-02 14:58:52 +02:00
|
|
|
ironlake_pch_transcoder_set_timings(crtc, PIPE_A);
|
2012-10-31 18:12:22 -02:00
|
|
|
|
2012-10-31 18:12:47 -02:00
|
|
|
lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
|
2011-01-05 10:31:48 -08:00
|
|
|
}
|
|
|
|
|
|
2013-05-03 11:49:50 +02:00
|
|
|
static void cpt_verify_modeset(struct drm_device *dev, int pipe)
|
2011-10-11 10:43:02 -07:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t dslreg = PIPEDSL(pipe);
|
2011-10-11 10:43:02 -07:00
|
|
|
u32 temp;
|
|
|
|
|
|
|
|
|
|
temp = I915_READ(dslreg);
|
|
|
|
|
udelay(500);
|
|
|
|
|
if (wait_for(I915_READ(dslreg) != temp, 5)) {
|
|
|
|
|
if (wait_for(I915_READ(dslreg) != temp, 5))
|
2013-04-17 17:48:49 +03:00
|
|
|
DRM_ERROR("mode set failed: pipe %c stuck\n", pipe_name(pipe));
|
2011-10-11 10:43:02 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 09:50:32 +02:00
|
|
|
static int
|
|
|
|
|
skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
|
2017-03-31 21:00:54 +03:00
|
|
|
unsigned int scaler_user, int *scaler_id,
|
2015-06-22 09:50:32 +02:00
|
|
|
int src_w, int src_h, int dst_w, int dst_h)
|
2015-04-07 15:28:45 -07:00
|
|
|
{
|
2015-06-22 09:50:32 +02:00
|
|
|
struct intel_crtc_scaler_state *scaler_state =
|
|
|
|
|
&crtc_state->scaler_state;
|
|
|
|
|
struct intel_crtc *intel_crtc =
|
|
|
|
|
to_intel_crtc(crtc_state->base.crtc);
|
2017-06-30 17:41:00 +05:30
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
|
|
|
|
const struct drm_display_mode *adjusted_mode =
|
|
|
|
|
&crtc_state->base.adjusted_mode;
|
2015-04-07 15:28:45 -07:00
|
|
|
int need_scaling;
|
2015-04-27 13:48:39 -07:00
|
|
|
|
2017-03-31 21:00:54 +03:00
|
|
|
/*
|
|
|
|
|
* Src coordinates are already rotated by 270 degrees for
|
|
|
|
|
* the 90/270 degree plane rotation cases (to match the
|
|
|
|
|
* GTT mapping), hence no need to account for rotation here.
|
|
|
|
|
*/
|
|
|
|
|
need_scaling = src_w != dst_w || src_h != dst_h;
|
2015-04-07 15:28:45 -07:00
|
|
|
|
2017-07-21 20:55:05 +05:30
|
|
|
if (crtc_state->ycbcr420 && scaler_user == SKL_CRTC_INDEX)
|
|
|
|
|
need_scaling = true;
|
|
|
|
|
|
2017-06-30 17:41:00 +05:30
|
|
|
/*
|
|
|
|
|
* Scaling/fitting not supported in IF-ID mode in GEN9+
|
|
|
|
|
* TODO: Interlace fetch mode doesn't support YUV420 planar formats.
|
|
|
|
|
* Once NV12 is enabled, handle it here while allocating scaler
|
|
|
|
|
* for NV12.
|
|
|
|
|
*/
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9 && crtc_state->base.enable &&
|
|
|
|
|
need_scaling && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
|
|
|
|
DRM_DEBUG_KMS("Pipe/Plane scaling not supported with IF-ID mode\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-07 15:28:45 -07:00
|
|
|
/*
|
|
|
|
|
* if plane is being disabled or scaler is no more required or force detach
|
|
|
|
|
* - free scaler binded to this plane/crtc
|
|
|
|
|
* - in order to do this, update crtc->scaler_usage
|
|
|
|
|
*
|
|
|
|
|
* Here scaler state in crtc_state is set free so that
|
|
|
|
|
* scaler can be assigned to other user. Actual register
|
|
|
|
|
* update to free the scaler is done in plane/panel-fit programming.
|
|
|
|
|
* For this purpose crtc/plane_state->scaler_id isn't reset here.
|
|
|
|
|
*/
|
2015-06-22 09:50:32 +02:00
|
|
|
if (force_detach || !need_scaling) {
|
2015-04-07 15:28:45 -07:00
|
|
|
if (*scaler_id >= 0) {
|
2015-06-22 09:50:32 +02:00
|
|
|
scaler_state->scaler_users &= ~(1 << scaler_user);
|
2015-04-07 15:28:45 -07:00
|
|
|
scaler_state->scalers[*scaler_id].in_use = 0;
|
|
|
|
|
|
2015-06-22 09:50:32 +02:00
|
|
|
DRM_DEBUG_KMS("scaler_user index %u.%u: "
|
|
|
|
|
"Staged freeing scaler id %d scaler_users = 0x%x\n",
|
|
|
|
|
intel_crtc->pipe, scaler_user, *scaler_id,
|
2015-04-07 15:28:45 -07:00
|
|
|
scaler_state->scaler_users);
|
|
|
|
|
*scaler_id = -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* range checks */
|
|
|
|
|
if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
|
|
|
|
|
dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
|
|
|
|
|
|
|
|
|
|
src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
|
|
|
|
|
dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H) {
|
2015-06-22 09:50:32 +02:00
|
|
|
DRM_DEBUG_KMS("scaler_user index %u.%u: src %ux%u dst %ux%u "
|
2015-04-07 15:28:45 -07:00
|
|
|
"size is out of scaler range\n",
|
2015-06-22 09:50:32 +02:00
|
|
|
intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h);
|
2015-04-07 15:28:45 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 09:50:32 +02:00
|
|
|
/* mark this plane as a scaler user in crtc_state */
|
|
|
|
|
scaler_state->scaler_users |= (1 << scaler_user);
|
|
|
|
|
DRM_DEBUG_KMS("scaler_user index %u.%u: "
|
|
|
|
|
"staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n",
|
|
|
|
|
intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h,
|
|
|
|
|
scaler_state->scaler_users);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* skl_update_scaler_crtc - Stages update to scaler state for a given crtc.
|
|
|
|
|
*
|
|
|
|
|
* @state: crtc's scaler state
|
|
|
|
|
*
|
|
|
|
|
* Return
|
|
|
|
|
* 0 - scaler_usage updated successfully
|
|
|
|
|
* error - requested scaling cannot be supported or other error condition
|
|
|
|
|
*/
|
2015-07-13 16:30:15 +02:00
|
|
|
int skl_update_scaler_crtc(struct intel_crtc_state *state)
|
2015-06-22 09:50:32 +02:00
|
|
|
{
|
2015-09-08 13:40:49 +03:00
|
|
|
const struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode;
|
2015-06-22 09:50:32 +02:00
|
|
|
|
2015-07-13 16:30:15 +02:00
|
|
|
return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
|
2017-03-31 21:00:54 +03:00
|
|
|
&state->scaler_state.scaler_id,
|
2015-06-22 09:50:32 +02:00
|
|
|
state->pipe_src_w, state->pipe_src_h,
|
2015-09-25 16:38:56 +03:00
|
|
|
adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
|
2015-06-22 09:50:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* skl_update_scaler_plane - Stages update to scaler state for a given plane.
|
|
|
|
|
*
|
|
|
|
|
* @state: crtc's scaler state
|
|
|
|
|
* @plane_state: atomic plane state to update
|
|
|
|
|
*
|
|
|
|
|
* Return
|
|
|
|
|
* 0 - scaler_usage updated successfully
|
|
|
|
|
* error - requested scaling cannot be supported or other error condition
|
|
|
|
|
*/
|
2015-06-15 12:33:44 +02:00
|
|
|
static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state)
|
2015-06-22 09:50:32 +02:00
|
|
|
{
|
|
|
|
|
|
2015-06-15 12:33:44 +02:00
|
|
|
struct intel_plane *intel_plane =
|
|
|
|
|
to_intel_plane(plane_state->base.plane);
|
2015-06-22 09:50:32 +02:00
|
|
|
struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2016-07-26 19:06:59 +03:00
|
|
|
bool force_detach = !fb || !plane_state->base.visible;
|
2015-06-22 09:50:32 +02:00
|
|
|
|
|
|
|
|
ret = skl_update_scaler(crtc_state, force_detach,
|
|
|
|
|
drm_plane_index(&intel_plane->base),
|
|
|
|
|
&plane_state->scaler_id,
|
2016-07-26 19:06:59 +03:00
|
|
|
drm_rect_width(&plane_state->base.src) >> 16,
|
|
|
|
|
drm_rect_height(&plane_state->base.src) >> 16,
|
|
|
|
|
drm_rect_width(&plane_state->base.dst),
|
|
|
|
|
drm_rect_height(&plane_state->base.dst));
|
2015-06-22 09:50:32 +02:00
|
|
|
|
|
|
|
|
if (ret || plane_state->scaler_id < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2015-04-07 15:28:45 -07:00
|
|
|
/* check colorkey */
|
2018-02-02 22:42:31 +02:00
|
|
|
if (plane_state->ckey.flags) {
|
2016-05-27 20:59:20 +03:00
|
|
|
DRM_DEBUG_KMS("[PLANE:%d:%s] scaling with color key not allowed",
|
|
|
|
|
intel_plane->base.base.id,
|
|
|
|
|
intel_plane->base.name);
|
2015-04-07 15:28:45 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check src format */
|
2016-12-14 23:32:55 +02:00
|
|
|
switch (fb->format->format) {
|
2015-06-22 09:50:32 +02:00
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
|
case DRM_FORMAT_XRGB2101010:
|
|
|
|
|
case DRM_FORMAT_XBGR2101010:
|
|
|
|
|
case DRM_FORMAT_YUYV:
|
|
|
|
|
case DRM_FORMAT_YVYU:
|
|
|
|
|
case DRM_FORMAT_UYVY:
|
|
|
|
|
case DRM_FORMAT_VYUY:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2016-05-27 20:59:20 +03:00
|
|
|
DRM_DEBUG_KMS("[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n",
|
|
|
|
|
intel_plane->base.base.id, intel_plane->base.name,
|
2016-12-14 23:32:55 +02:00
|
|
|
fb->base.id, fb->format->format);
|
2015-06-22 09:50:32 +02:00
|
|
|
return -EINVAL;
|
2015-04-07 15:28:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-13 16:30:15 +02:00
|
|
|
static void skylake_scaler_disable(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < crtc->num_scalers; i++)
|
|
|
|
|
skl_detach_scaler(crtc, i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void skylake_pfit_enable(struct intel_crtc *crtc)
|
2014-11-13 17:51:47 +00:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-11-13 17:51:47 +00:00
|
|
|
int pipe = crtc->pipe;
|
2015-04-07 15:28:45 -07:00
|
|
|
struct intel_crtc_scaler_state *scaler_state =
|
|
|
|
|
&crtc->config->scaler_state;
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (crtc->config->pch_pfit.enabled) {
|
2015-04-07 15:28:45 -07:00
|
|
|
int id;
|
|
|
|
|
|
2017-03-07 22:54:19 +02:00
|
|
|
if (WARN_ON(crtc->config->scaler_state.scaler_id < 0))
|
2015-04-07 15:28:45 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
id = scaler_state->scaler_id;
|
|
|
|
|
I915_WRITE(SKL_PS_CTRL(pipe, id), PS_SCALER_EN |
|
|
|
|
|
PS_FILTER_MEDIUM | scaler_state->scalers[id].mode);
|
|
|
|
|
I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc->config->pch_pfit.pos);
|
|
|
|
|
I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc->config->pch_pfit.size);
|
2014-11-13 17:51:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-25 12:55:02 -07:00
|
|
|
static void ironlake_pfit_enable(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-04-25 12:55:02 -07:00
|
|
|
int pipe = crtc->pipe;
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (crtc->config->pch_pfit.enabled) {
|
2013-04-25 12:55:02 -07:00
|
|
|
/* Force use of hard-coded filter coefficients
|
|
|
|
|
* as some pre-programmed values are broken,
|
|
|
|
|
* e.g. x201.
|
|
|
|
|
*/
|
2016-10-14 10:13:06 +01:00
|
|
|
if (IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv))
|
2013-04-25 12:55:02 -07:00
|
|
|
I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 |
|
|
|
|
|
PF_PIPE_SEL_IVB(pipe));
|
|
|
|
|
else
|
|
|
|
|
I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
|
2015-01-15 14:55:25 +02:00
|
|
|
I915_WRITE(PF_WIN_POS(pipe), crtc->config->pch_pfit.pos);
|
|
|
|
|
I915_WRITE(PF_WIN_SZ(pipe), crtc->config->pch_pfit.size);
|
2011-10-11 10:43:02 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-10 12:35:00 +01:00
|
|
|
void hsw_enable_ips(const struct intel_crtc_state *crtc_state)
|
2013-09-24 13:52:55 -03:00
|
|
|
{
|
2017-11-10 12:35:00 +01:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
2014-04-15 21:41:35 +03:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-09-24 13:52:55 -03:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (!crtc_state->ips_enabled)
|
2013-09-24 13:52:55 -03:00
|
|
|
return;
|
|
|
|
|
|
2016-03-23 14:33:28 +01:00
|
|
|
/*
|
|
|
|
|
* We can only enable IPS after we enable a plane and wait for a vblank
|
|
|
|
|
* This function is called from post_plane_update, which is run after
|
|
|
|
|
* a vblank wait.
|
|
|
|
|
*/
|
2017-11-22 19:39:01 +01:00
|
|
|
WARN_ON(!(crtc_state->active_planes & ~BIT(PLANE_CURSOR)));
|
2017-11-17 21:19:08 +02:00
|
|
|
|
2016-10-13 11:03:00 +01:00
|
|
|
if (IS_BROADWELL(dev_priv)) {
|
2017-10-10 22:30:05 +01:00
|
|
|
mutex_lock(&dev_priv->pcu_lock);
|
2017-09-12 18:34:11 +03:00
|
|
|
WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL,
|
|
|
|
|
IPS_ENABLE | IPS_PCODE_CONTROL));
|
2017-10-10 22:30:05 +01:00
|
|
|
mutex_unlock(&dev_priv->pcu_lock);
|
2013-11-02 21:07:47 -07:00
|
|
|
/* Quoting Art Runyan: "its not safe to expect any particular
|
|
|
|
|
* value in IPS_CTL bit 31 after enabling IPS through the
|
2014-01-07 13:30:45 -08:00
|
|
|
* mailbox." Moreover, the mailbox may return a bogus state,
|
|
|
|
|
* so we need to just enable it and continue on.
|
2013-11-02 21:07:47 -07:00
|
|
|
*/
|
|
|
|
|
} else {
|
|
|
|
|
I915_WRITE(IPS_CTL, IPS_ENABLE);
|
|
|
|
|
/* The bit only becomes 1 in the next vblank, so this wait here
|
|
|
|
|
* is essentially intel_wait_for_vblank. If we don't have this
|
|
|
|
|
* and don't wait for vblanks until the end of crtc_enable, then
|
|
|
|
|
* the HW state readout code will complain that the expected
|
|
|
|
|
* IPS_CTL value is not the one we read. */
|
2016-06-30 15:33:01 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
IPS_CTL, IPS_ENABLE, IPS_ENABLE,
|
|
|
|
|
50))
|
2013-11-02 21:07:47 -07:00
|
|
|
DRM_ERROR("Timed out waiting for IPS enable\n");
|
|
|
|
|
}
|
2013-09-24 13:52:55 -03:00
|
|
|
}
|
|
|
|
|
|
2017-11-10 12:35:00 +01:00
|
|
|
void hsw_disable_ips(const struct intel_crtc_state *crtc_state)
|
2013-09-24 13:52:55 -03:00
|
|
|
{
|
2017-11-10 12:35:00 +01:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
2013-09-24 13:52:55 -03:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-09-24 13:52:55 -03:00
|
|
|
|
2017-11-10 12:35:00 +01:00
|
|
|
if (!crtc_state->ips_enabled)
|
2013-09-24 13:52:55 -03:00
|
|
|
return;
|
|
|
|
|
|
2016-10-13 11:03:00 +01:00
|
|
|
if (IS_BROADWELL(dev_priv)) {
|
2017-10-10 22:30:05 +01:00
|
|
|
mutex_lock(&dev_priv->pcu_lock);
|
2013-11-02 21:07:47 -07:00
|
|
|
WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
|
2017-10-10 22:30:05 +01:00
|
|
|
mutex_unlock(&dev_priv->pcu_lock);
|
2014-04-10 14:32:41 -07:00
|
|
|
/* wait for pcode to finish disabling IPS, which may take up to 42ms */
|
2016-06-30 15:33:02 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
IPS_CTL, IPS_ENABLE, 0,
|
|
|
|
|
42))
|
2014-04-10 14:32:41 -07:00
|
|
|
DRM_ERROR("Timed out waiting for IPS disable\n");
|
2014-01-07 13:30:45 -08:00
|
|
|
} else {
|
2013-11-02 21:07:47 -07:00
|
|
|
I915_WRITE(IPS_CTL, 0);
|
2014-01-07 13:30:45 -08:00
|
|
|
POSTING_READ(IPS_CTL);
|
|
|
|
|
}
|
2013-09-24 13:52:55 -03:00
|
|
|
|
|
|
|
|
/* We need to wait for a vblank before we can disable the plane. */
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, crtc->pipe);
|
2013-09-24 13:52:55 -03:00
|
|
|
}
|
|
|
|
|
|
2015-04-21 17:12:55 +03:00
|
|
|
static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc)
|
2014-05-08 19:23:13 +03:00
|
|
|
{
|
2015-04-21 17:12:55 +03:00
|
|
|
if (intel_crtc->overlay) {
|
2014-05-08 19:23:13 +03:00
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev->struct_mutex);
|
|
|
|
|
(void) intel_overlay_switch_off(intel_crtc->overlay);
|
|
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Let userspace switch the overlay on again. In most cases userspace
|
|
|
|
|
* has to recompute where to put it anyway.
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-21 17:12:54 +03:00
|
|
|
/**
|
|
|
|
|
* intel_post_enable_primary - Perform operations after enabling primary plane
|
|
|
|
|
* @crtc: the CRTC whose primary plane was just enabled
|
|
|
|
|
*
|
|
|
|
|
* Performs potentially sleeping operations that must be done after the primary
|
|
|
|
|
* plane is enabled, such as updating FBC and IPS. Note that this may be
|
|
|
|
|
* called due to an explicit primary plane update, or due to an implicit
|
|
|
|
|
* re-enable that is caused when a sprite plane is updated to no longer
|
|
|
|
|
* completely hide the primary plane.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-11-10 12:35:00 +01:00
|
|
|
intel_post_enable_primary(struct drm_crtc *crtc,
|
|
|
|
|
const struct intel_crtc_state *new_crtc_state)
|
2014-03-07 18:32:13 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-03-07 18:32:13 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
|
|
|
|
|
drm/i915: Track frontbuffer invalidation/flushing
So these are the guts of the new beast. This tracks when a frontbuffer
gets invalidated (due to frontbuffer rendering) and hence should be
constantly scaned out, and when it's flushed again and can be
compressed/one-shot-upload.
Rules for flushing are simple: The frontbuffer needs one more full
upload starting from the next vblank. Which means that the flushing
can _only_ be called once the frontbuffer update has been latched.
But this poses a problem for pageflips: We can't just delay the
flushing until the pageflip is latched, since that would pose the risk
that we override frontbuffer rendering that has been scheduled
in-between the pageflip ioctl and the actual latching.
To handle this track asynchronous invalidations (and also pageflip)
state per-ring and delay any in-between flushing until the rendering
has completed. And also cancel any delayed flushing if we get a new
invalidation request (whether delayed or not).
Also call intel_mark_fb_busy in both cases in all cases to make sure
that we keep the screen at the highest refresh rate both on flips,
synchronous plane updates and for frontbuffer rendering.
v2: Lots of improvements
Suggestions from Chris:
- Move invalidate/flush in flush_*_domain and set_to_*_domain.
- Drop the flush in busy_ioctl since it's redundant. Was a leftover
from an earlier concept to track flips/delayed flushes.
- Don't forget about the initial modeset enable/final disable.
Suggested by Chris.
Track flips accurately, too. Since flips complete independently of
rendering we need to track pending flips in a separate mask. Again if
an invalidate happens we need to cancel the evenutal flush to avoid
races.
v3:
Provide correct header declarations for flip functions. Currently not
needed outside of intel_display.c, but part of the proper interface.
v4: Add proper domain management to fbcon so that the fbcon buffer is
also tracked correctly.
v5: Fixup locking around the fbcon set_to_gtt_domain call.
v6: More comments from Chris:
- Split out fbcon changes.
- Drop superflous checks for potential scanout before calling intel_fb
functions - we can micro-optimize this later.
- s/intel_fb_/intel_fb_obj_/ to make it clear that this deals in gem
object. We already have precedence for fb_obj in the pin_and_fence
functions.
v7: Clarify the semantics of the flip flush handling by renaming
things a bit:
- Don't go through a gem object but take the relevant frontbuffer bits
directly. These functions center on the plane, the actual object is
irrelevant - even a flip to the same object as already active should
cause a flush.
- Add a new intel_frontbuffer_flip for synchronous plane updates. It
currently just calls intel_frontbuffer_flush since the implemenation
differs.
This way we achieve a clear split between one-shot update events on
one side and frontbuffer rendering with potentially a very long delay
between the invalidate and flush.
Chris and I also had some discussions about mark_busy and whether it
is appropriate to call from flush. But mark busy is a state which
should be derived from the 3 events (invalidate, flush, flip) we now
have by the users, like psr does by tracking relevant information in
psr.busy_frontbuffer_bits. DRRS (the only real use of mark_busy for
frontbuffer) needs to have similar logic. With that the overall
mark_busy in the core could be removed.
v8: Only when retiring gpu buffers only flush frontbuffer bits we
actually invalidated in a batch. Just for safety since before any
additional usage/invalidate we should always retire current rendering.
Suggested by Chris Wilson.
v9: Actually use intel_frontbuffer_flip in all appropriate places.
Spotted by Chris.
v10: Address more comments from Chris:
- Don't call _flip in set_base when the crtc is inactive, avoids redunancy
in the modeset case with the initial enabling of all planes.
- Add comments explaining that the initial/final plane enable/disable
still has work left to do before it's fully generic.
v11: Only invalidate for gtt/cpu access when writing. Spotted by Chris.
v12: s/_flush/_flip/ in intel_overlay.c per Chris' comment.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2014-06-19 16:01:59 +02:00
|
|
|
/*
|
2015-04-21 17:12:54 +03:00
|
|
|
* Gen2 reports pipe underruns whenever all planes are disabled.
|
|
|
|
|
* So don't enable underrun reporting before at least some planes
|
|
|
|
|
* are enabled.
|
|
|
|
|
* FIXME: Need to fix the logic to work when we turn off all planes
|
|
|
|
|
* but leave the pipe running.
|
drm/i915: Track frontbuffer invalidation/flushing
So these are the guts of the new beast. This tracks when a frontbuffer
gets invalidated (due to frontbuffer rendering) and hence should be
constantly scaned out, and when it's flushed again and can be
compressed/one-shot-upload.
Rules for flushing are simple: The frontbuffer needs one more full
upload starting from the next vblank. Which means that the flushing
can _only_ be called once the frontbuffer update has been latched.
But this poses a problem for pageflips: We can't just delay the
flushing until the pageflip is latched, since that would pose the risk
that we override frontbuffer rendering that has been scheduled
in-between the pageflip ioctl and the actual latching.
To handle this track asynchronous invalidations (and also pageflip)
state per-ring and delay any in-between flushing until the rendering
has completed. And also cancel any delayed flushing if we get a new
invalidation request (whether delayed or not).
Also call intel_mark_fb_busy in both cases in all cases to make sure
that we keep the screen at the highest refresh rate both on flips,
synchronous plane updates and for frontbuffer rendering.
v2: Lots of improvements
Suggestions from Chris:
- Move invalidate/flush in flush_*_domain and set_to_*_domain.
- Drop the flush in busy_ioctl since it's redundant. Was a leftover
from an earlier concept to track flips/delayed flushes.
- Don't forget about the initial modeset enable/final disable.
Suggested by Chris.
Track flips accurately, too. Since flips complete independently of
rendering we need to track pending flips in a separate mask. Again if
an invalidate happens we need to cancel the evenutal flush to avoid
races.
v3:
Provide correct header declarations for flip functions. Currently not
needed outside of intel_display.c, but part of the proper interface.
v4: Add proper domain management to fbcon so that the fbcon buffer is
also tracked correctly.
v5: Fixup locking around the fbcon set_to_gtt_domain call.
v6: More comments from Chris:
- Split out fbcon changes.
- Drop superflous checks for potential scanout before calling intel_fb
functions - we can micro-optimize this later.
- s/intel_fb_/intel_fb_obj_/ to make it clear that this deals in gem
object. We already have precedence for fb_obj in the pin_and_fence
functions.
v7: Clarify the semantics of the flip flush handling by renaming
things a bit:
- Don't go through a gem object but take the relevant frontbuffer bits
directly. These functions center on the plane, the actual object is
irrelevant - even a flip to the same object as already active should
cause a flush.
- Add a new intel_frontbuffer_flip for synchronous plane updates. It
currently just calls intel_frontbuffer_flush since the implemenation
differs.
This way we achieve a clear split between one-shot update events on
one side and frontbuffer rendering with potentially a very long delay
between the invalidate and flush.
Chris and I also had some discussions about mark_busy and whether it
is appropriate to call from flush. But mark busy is a state which
should be derived from the 3 events (invalidate, flush, flip) we now
have by the users, like psr does by tracking relevant information in
psr.busy_frontbuffer_bits. DRRS (the only real use of mark_busy for
frontbuffer) needs to have similar logic. With that the overall
mark_busy in the core could be removed.
v8: Only when retiring gpu buffers only flush frontbuffer bits we
actually invalidated in a batch. Just for safety since before any
additional usage/invalidate we should always retire current rendering.
Suggested by Chris Wilson.
v9: Actually use intel_frontbuffer_flip in all appropriate places.
Spotted by Chris.
v10: Address more comments from Chris:
- Don't call _flip in set_base when the crtc is inactive, avoids redunancy
in the modeset case with the initial enabling of all planes.
- Add comments explaining that the initial/final plane enable/disable
still has work left to do before it's fully generic.
v11: Only invalidate for gtt/cpu access when writing. Spotted by Chris.
v12: s/_flush/_flip/ in intel_overlay.c per Chris' comment.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2014-06-19 16:01:59 +02:00
|
|
|
*/
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN2(dev_priv))
|
2015-04-21 17:12:54 +03:00
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
|
|
|
|
|
2015-10-30 19:22:21 +02:00
|
|
|
/* Underruns don't always raise interrupts, so check manually. */
|
|
|
|
|
intel_check_cpu_fifo_underruns(dev_priv);
|
|
|
|
|
intel_check_pch_fifo_underruns(dev_priv);
|
2014-03-07 18:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
/* FIXME get rid of this and use pre_plane_update */
|
2015-04-21 17:12:54 +03:00
|
|
|
static void
|
2017-11-22 19:39:01 +01:00
|
|
|
intel_pre_disable_primary_noatomic(struct drm_crtc *crtc)
|
2014-03-07 18:32:13 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-03-07 18:32:13 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
|
|
|
|
|
2015-04-21 17:12:54 +03:00
|
|
|
/*
|
|
|
|
|
* Gen2 reports pipe underruns whenever all planes are disabled.
|
2017-11-22 19:39:01 +01:00
|
|
|
* So disable underrun reporting before all the planes get disabled.
|
2015-04-21 17:12:54 +03:00
|
|
|
*/
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN2(dev_priv))
|
2015-04-21 17:12:54 +03:00
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
|
2014-03-07 18:32:13 +02:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
hsw_disable_ips(to_intel_crtc_state(crtc->state));
|
2016-03-09 19:07:26 +02:00
|
|
|
|
2015-04-21 17:12:54 +03:00
|
|
|
/*
|
|
|
|
|
* Vblank time updates from the shadow to live plane control register
|
|
|
|
|
* are blocked if the memory self-refresh mode is active at that
|
|
|
|
|
* moment. So to make sure the plane gets truly disabled, disable
|
|
|
|
|
* first the self-refresh mode. The self-refresh enable bit in turn
|
|
|
|
|
* will be checked/applied by the HW only at the next frame start
|
|
|
|
|
* event which is after the vblank start event, so we need to have a
|
|
|
|
|
* wait-for-vblank between disabling the plane and the pipe.
|
|
|
|
|
*/
|
2016-11-28 19:37:12 +02:00
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv) &&
|
|
|
|
|
intel_set_memory_cxsr(dev_priv, false))
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, pipe);
|
2015-04-21 17:12:54 +03:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
static bool hsw_pre_update_disable_ips(const struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
const struct intel_crtc_state *new_crtc_state)
|
|
|
|
|
{
|
|
|
|
|
if (!old_crtc_state->ips_enabled)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (needs_modeset(&new_crtc_state->base))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return !new_crtc_state->ips_enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool hsw_post_update_enable_ips(const struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
const struct intel_crtc_state *new_crtc_state)
|
|
|
|
|
{
|
|
|
|
|
if (!new_crtc_state->ips_enabled)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (needs_modeset(&new_crtc_state->base))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We can't read out IPS on broadwell, assume the worst and
|
|
|
|
|
* forcibly enable IPS on the first fastset.
|
|
|
|
|
*/
|
|
|
|
|
if (new_crtc_state->update_pipe &&
|
|
|
|
|
old_crtc_state->base.adjusted_mode.private_flags & I915_MODE_FLAG_INHERITED)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return !old_crtc_state->ips_enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
static void intel_post_plane_update(struct intel_crtc_state *old_crtc_state)
|
|
|
|
|
{
|
|
|
|
|
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
|
|
|
|
|
struct drm_atomic_state *old_state = old_crtc_state->base.state;
|
|
|
|
|
struct intel_crtc_state *pipe_config =
|
2017-08-23 18:22:24 +03:00
|
|
|
intel_atomic_get_new_crtc_state(to_intel_atomic_state(old_state),
|
|
|
|
|
crtc);
|
2016-05-24 17:13:53 +02:00
|
|
|
struct drm_plane *primary = crtc->base.primary;
|
|
|
|
|
struct drm_plane_state *old_pri_state =
|
|
|
|
|
drm_atomic_get_existing_plane_state(old_state, primary);
|
|
|
|
|
|
2016-08-04 16:32:38 +01:00
|
|
|
intel_frontbuffer_flip(to_i915(crtc->base.dev), pipe_config->fb_bits);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
if (pipe_config->update_wm_post && pipe_config->base.active)
|
2016-10-31 22:37:03 +02:00
|
|
|
intel_update_watermarks(crtc);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (hsw_post_update_enable_ips(old_crtc_state, pipe_config))
|
|
|
|
|
hsw_enable_ips(pipe_config);
|
|
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
if (old_pri_state) {
|
|
|
|
|
struct intel_plane_state *primary_state =
|
2017-08-23 18:22:24 +03:00
|
|
|
intel_atomic_get_new_plane_state(to_intel_atomic_state(old_state),
|
|
|
|
|
to_intel_plane(primary));
|
2016-05-24 17:13:53 +02:00
|
|
|
struct intel_plane_state *old_primary_state =
|
|
|
|
|
to_intel_plane_state(old_pri_state);
|
|
|
|
|
|
|
|
|
|
intel_fbc_post_update(crtc);
|
|
|
|
|
|
2016-07-26 19:06:59 +03:00
|
|
|
if (primary_state->base.visible &&
|
2016-05-24 17:13:53 +02:00
|
|
|
(needs_modeset(&pipe_config->base) ||
|
2016-07-26 19:06:59 +03:00
|
|
|
!old_primary_state->base.visible))
|
2017-11-10 12:35:00 +01:00
|
|
|
intel_post_enable_primary(&crtc->base, pipe_config);
|
2016-05-24 17:13:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
2015-06-15 12:33:49 +02:00
|
|
|
{
|
2016-02-03 16:53:24 +01:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
|
2015-06-15 12:33:49 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-02-03 16:53:24 +01:00
|
|
|
struct drm_atomic_state *old_state = old_crtc_state->base.state;
|
|
|
|
|
struct drm_plane *primary = crtc->base.primary;
|
|
|
|
|
struct drm_plane_state *old_pri_state =
|
|
|
|
|
drm_atomic_get_existing_plane_state(old_state, primary);
|
|
|
|
|
bool modeset = needs_modeset(&pipe_config->base);
|
2016-11-08 13:55:32 +01:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_state);
|
2015-06-15 12:33:49 +02:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (hsw_pre_update_disable_ips(old_crtc_state, pipe_config))
|
|
|
|
|
hsw_disable_ips(old_crtc_state);
|
|
|
|
|
|
2016-02-03 16:53:24 +01:00
|
|
|
if (old_pri_state) {
|
|
|
|
|
struct intel_plane_state *primary_state =
|
2017-08-23 18:22:24 +03:00
|
|
|
intel_atomic_get_new_plane_state(old_intel_state,
|
|
|
|
|
to_intel_plane(primary));
|
2016-02-03 16:53:24 +01:00
|
|
|
struct intel_plane_state *old_primary_state =
|
|
|
|
|
to_intel_plane_state(old_pri_state);
|
|
|
|
|
|
2016-06-14 14:24:20 +02:00
|
|
|
intel_fbc_pre_update(crtc, pipe_config, primary_state);
|
2017-11-22 19:39:01 +01:00
|
|
|
/*
|
|
|
|
|
* Gen2 reports pipe underruns whenever all planes are disabled.
|
|
|
|
|
* So disable underrun reporting before all the planes get disabled.
|
|
|
|
|
*/
|
|
|
|
|
if (IS_GEN2(dev_priv) && old_primary_state->base.visible &&
|
2016-07-26 19:06:59 +03:00
|
|
|
(modeset || !primary_state->base.visible))
|
2017-11-22 19:39:01 +01:00
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
|
2016-02-03 16:53:24 +01:00
|
|
|
}
|
2015-06-24 22:00:07 +03:00
|
|
|
|
2017-03-02 19:15:00 +02:00
|
|
|
/*
|
|
|
|
|
* Vblank time updates from the shadow to live plane control register
|
|
|
|
|
* are blocked if the memory self-refresh mode is active at that
|
|
|
|
|
* moment. So to make sure the plane gets truly disabled, disable
|
|
|
|
|
* first the self-refresh mode. The self-refresh enable bit in turn
|
|
|
|
|
* will be checked/applied by the HW only at the next frame start
|
|
|
|
|
* event which is after the vblank start event, so we need to have a
|
|
|
|
|
* wait-for-vblank between disabling the plane and the pipe.
|
|
|
|
|
*/
|
|
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv) && old_crtc_state->base.active &&
|
|
|
|
|
pipe_config->disable_cxsr && intel_set_memory_cxsr(dev_priv, false))
|
|
|
|
|
intel_wait_for_vblank(dev_priv, crtc->pipe);
|
2015-12-03 13:49:13 +01:00
|
|
|
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2016-11-28 19:37:04 +02:00
|
|
|
if (pipe_config->disable_lp_wm && ilk_disable_lp_wm(dev))
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, crtc->pipe);
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we're doing a modeset, we're done. No need to do any pre-vblank
|
|
|
|
|
* watermark programming here.
|
|
|
|
|
*/
|
|
|
|
|
if (needs_modeset(&pipe_config->base))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For platforms that support atomic watermarks, program the
|
|
|
|
|
* 'intermediate' watermarks immediately. On pre-gen9 platforms, these
|
|
|
|
|
* will be the intermediate values that are safe for both pre- and
|
|
|
|
|
* post- vblank; when vblank happens, the 'active' values will be set
|
|
|
|
|
* to the final 'target' values and we'll do this again to get the
|
|
|
|
|
* optimal watermarks. For gen9+ platforms, the values we program here
|
|
|
|
|
* will be the final target values which will get automatically latched
|
|
|
|
|
* at vblank time; no further programming will be necessary.
|
|
|
|
|
*
|
|
|
|
|
* If a platform hasn't been transitioned to atomic watermarks yet,
|
|
|
|
|
* we'll continue to update watermarks the old way, if flags tell
|
|
|
|
|
* us to.
|
|
|
|
|
*/
|
|
|
|
|
if (dev_priv->display.initial_watermarks != NULL)
|
2016-11-08 13:55:32 +01:00
|
|
|
dev_priv->display.initial_watermarks(old_intel_state,
|
|
|
|
|
pipe_config);
|
2016-03-09 19:07:25 +02:00
|
|
|
else if (pipe_config->update_wm_pre)
|
2016-10-31 22:37:03 +02:00
|
|
|
intel_update_watermarks(crtc);
|
2015-06-15 12:33:49 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-15 12:33:51 +02:00
|
|
|
static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask)
|
2015-04-21 17:12:54 +03:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2015-06-15 12:33:51 +02:00
|
|
|
struct drm_plane *p;
|
2015-04-21 17:12:54 +03:00
|
|
|
int pipe = intel_crtc->pipe;
|
|
|
|
|
|
2015-04-21 17:12:55 +03:00
|
|
|
intel_crtc_dpms_overlay_disable(intel_crtc);
|
2015-04-21 17:12:52 +03:00
|
|
|
|
2015-06-15 12:33:51 +02:00
|
|
|
drm_for_each_plane_mask(p, dev, plane_mask)
|
2017-03-27 21:55:33 +03:00
|
|
|
to_intel_plane(p)->disable_plane(to_intel_plane(p), intel_crtc);
|
2014-05-22 17:48:06 +03:00
|
|
|
|
drm/i915: Track frontbuffer invalidation/flushing
So these are the guts of the new beast. This tracks when a frontbuffer
gets invalidated (due to frontbuffer rendering) and hence should be
constantly scaned out, and when it's flushed again and can be
compressed/one-shot-upload.
Rules for flushing are simple: The frontbuffer needs one more full
upload starting from the next vblank. Which means that the flushing
can _only_ be called once the frontbuffer update has been latched.
But this poses a problem for pageflips: We can't just delay the
flushing until the pageflip is latched, since that would pose the risk
that we override frontbuffer rendering that has been scheduled
in-between the pageflip ioctl and the actual latching.
To handle this track asynchronous invalidations (and also pageflip)
state per-ring and delay any in-between flushing until the rendering
has completed. And also cancel any delayed flushing if we get a new
invalidation request (whether delayed or not).
Also call intel_mark_fb_busy in both cases in all cases to make sure
that we keep the screen at the highest refresh rate both on flips,
synchronous plane updates and for frontbuffer rendering.
v2: Lots of improvements
Suggestions from Chris:
- Move invalidate/flush in flush_*_domain and set_to_*_domain.
- Drop the flush in busy_ioctl since it's redundant. Was a leftover
from an earlier concept to track flips/delayed flushes.
- Don't forget about the initial modeset enable/final disable.
Suggested by Chris.
Track flips accurately, too. Since flips complete independently of
rendering we need to track pending flips in a separate mask. Again if
an invalidate happens we need to cancel the evenutal flush to avoid
races.
v3:
Provide correct header declarations for flip functions. Currently not
needed outside of intel_display.c, but part of the proper interface.
v4: Add proper domain management to fbcon so that the fbcon buffer is
also tracked correctly.
v5: Fixup locking around the fbcon set_to_gtt_domain call.
v6: More comments from Chris:
- Split out fbcon changes.
- Drop superflous checks for potential scanout before calling intel_fb
functions - we can micro-optimize this later.
- s/intel_fb_/intel_fb_obj_/ to make it clear that this deals in gem
object. We already have precedence for fb_obj in the pin_and_fence
functions.
v7: Clarify the semantics of the flip flush handling by renaming
things a bit:
- Don't go through a gem object but take the relevant frontbuffer bits
directly. These functions center on the plane, the actual object is
irrelevant - even a flip to the same object as already active should
cause a flush.
- Add a new intel_frontbuffer_flip for synchronous plane updates. It
currently just calls intel_frontbuffer_flush since the implemenation
differs.
This way we achieve a clear split between one-shot update events on
one side and frontbuffer rendering with potentially a very long delay
between the invalidate and flush.
Chris and I also had some discussions about mark_busy and whether it
is appropriate to call from flush. But mark busy is a state which
should be derived from the 3 events (invalidate, flush, flip) we now
have by the users, like psr does by tracking relevant information in
psr.busy_frontbuffer_bits. DRRS (the only real use of mark_busy for
frontbuffer) needs to have similar logic. With that the overall
mark_busy in the core could be removed.
v8: Only when retiring gpu buffers only flush frontbuffer bits we
actually invalidated in a batch. Just for safety since before any
additional usage/invalidate we should always retire current rendering.
Suggested by Chris Wilson.
v9: Actually use intel_frontbuffer_flip in all appropriate places.
Spotted by Chris.
v10: Address more comments from Chris:
- Don't call _flip in set_base when the crtc is inactive, avoids redunancy
in the modeset case with the initial enabling of all planes.
- Add comments explaining that the initial/final plane enable/disable
still has work left to do before it's fully generic.
v11: Only invalidate for gtt/cpu access when writing. Spotted by Chris.
v12: s/_flush/_flip/ in intel_overlay.c per Chris' comment.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2014-06-19 16:01:59 +02:00
|
|
|
/*
|
|
|
|
|
* FIXME: Once we grow proper nuclear flip support out of this we need
|
|
|
|
|
* to compute the mask of flip planes precisely. For the time being
|
|
|
|
|
* consider this a flip to a NULL plane.
|
|
|
|
|
*/
|
2016-08-04 16:32:38 +01:00
|
|
|
intel_frontbuffer_flip(to_i915(dev), INTEL_FRONTBUFFER_ALL_MASK(pipe));
|
2014-03-07 18:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-09 17:04:03 +02:00
|
|
|
static void intel_encoders_pre_pll_enable(struct drm_crtc *crtc,
|
2016-08-09 17:04:04 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_atomic_state *old_state)
|
|
|
|
|
{
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_connector_state *conn_state;
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_connector *conn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(old_state, conn, conn_state, i) {
|
2016-08-09 17:04:03 +02:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
to_intel_encoder(conn_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
if (conn_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (encoder->pre_pll_enable)
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->pre_pll_enable(encoder, crtc_state, conn_state);
|
2016-08-09 17:04:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_encoders_pre_enable(struct drm_crtc *crtc,
|
2016-08-09 17:04:04 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_atomic_state *old_state)
|
|
|
|
|
{
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_connector_state *conn_state;
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_connector *conn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(old_state, conn, conn_state, i) {
|
2016-08-09 17:04:03 +02:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
to_intel_encoder(conn_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
if (conn_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (encoder->pre_enable)
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->pre_enable(encoder, crtc_state, conn_state);
|
2016-08-09 17:04:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_encoders_enable(struct drm_crtc *crtc,
|
2016-08-09 17:04:04 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_atomic_state *old_state)
|
|
|
|
|
{
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_connector_state *conn_state;
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_connector *conn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(old_state, conn, conn_state, i) {
|
2016-08-09 17:04:03 +02:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
to_intel_encoder(conn_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
if (conn_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->enable(encoder, crtc_state, conn_state);
|
2016-08-09 17:04:03 +02:00
|
|
|
intel_opregion_notify_encoder(encoder, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_encoders_disable(struct drm_crtc *crtc,
|
2016-08-09 17:04:04 +02:00
|
|
|
struct intel_crtc_state *old_crtc_state,
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_atomic_state *old_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_connector_state *old_conn_state;
|
|
|
|
|
struct drm_connector *conn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
|
2016-08-09 17:04:03 +02:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
to_intel_encoder(old_conn_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
if (old_conn_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
intel_opregion_notify_encoder(encoder, false);
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->disable(encoder, old_crtc_state, old_conn_state);
|
2016-08-09 17:04:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_encoders_post_disable(struct drm_crtc *crtc,
|
2016-08-09 17:04:04 +02:00
|
|
|
struct intel_crtc_state *old_crtc_state,
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_atomic_state *old_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_connector_state *old_conn_state;
|
|
|
|
|
struct drm_connector *conn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
|
2016-08-09 17:04:03 +02:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
to_intel_encoder(old_conn_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
if (old_conn_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (encoder->post_disable)
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->post_disable(encoder, old_crtc_state, old_conn_state);
|
2016-08-09 17:04:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_encoders_post_pll_disable(struct drm_crtc *crtc,
|
2016-08-09 17:04:04 +02:00
|
|
|
struct intel_crtc_state *old_crtc_state,
|
2016-08-09 17:04:03 +02:00
|
|
|
struct drm_atomic_state *old_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_connector_state *old_conn_state;
|
|
|
|
|
struct drm_connector *conn;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
|
2016-08-09 17:04:03 +02:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
to_intel_encoder(old_conn_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
if (old_conn_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (encoder->post_pll_disable)
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->post_pll_disable(encoder, old_crtc_state, old_conn_state);
|
2016-08-09 17:04:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-09 17:04:01 +02:00
|
|
|
static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2011-01-05 10:31:48 -08:00
|
|
|
{
|
2016-08-09 17:04:01 +02:00
|
|
|
struct drm_crtc *crtc = pipe_config->base.crtc;
|
2011-01-05 10:31:48 -08:00
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2011-01-05 10:31:48 -08:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
2016-11-08 13:55:32 +01:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_state);
|
2011-01-05 10:31:48 -08:00
|
|
|
|
2015-06-01 12:49:52 +02:00
|
|
|
if (WARN_ON(intel_crtc->active))
|
2011-01-05 10:31:48 -08:00
|
|
|
return;
|
|
|
|
|
|
2016-04-01 21:53:17 +03:00
|
|
|
/*
|
|
|
|
|
* Sometimes spurious CPU pipe underruns happen during FDI
|
|
|
|
|
* training, at least with VGA+HDMI cloning. Suppress them.
|
|
|
|
|
*
|
|
|
|
|
* On ILK we get an occasional spurious CPU pipe underruns
|
|
|
|
|
* between eDP port A enable and vdd enable. Also PCH port
|
|
|
|
|
* enable seems to result in the occasional CPU pipe underrun.
|
|
|
|
|
*
|
|
|
|
|
* Spurious PCH underruns also occur during PCH enabling.
|
|
|
|
|
*/
|
|
|
|
|
if (intel_crtc->config->has_pch_encoder || IS_GEN5(dev_priv))
|
|
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
|
2015-10-30 19:21:31 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder)
|
|
|
|
|
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder)
|
2014-04-24 23:55:13 +02:00
|
|
|
intel_prepare_shared_dpll(intel_crtc);
|
|
|
|
|
|
2016-06-22 21:57:04 +03:00
|
|
|
if (intel_crtc_has_dp_encoder(intel_crtc->config))
|
2015-02-13 15:32:59 +05:30
|
|
|
intel_dp_set_m_n(intel_crtc, M1_N1);
|
2014-04-24 23:55:08 +02:00
|
|
|
|
|
|
|
|
intel_set_pipe_timings(intel_crtc);
|
2016-03-18 17:05:39 +02:00
|
|
|
intel_set_pipe_src_size(intel_crtc);
|
2014-04-24 23:55:08 +02:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder) {
|
2014-04-24 23:55:08 +02:00
|
|
|
intel_cpu_transcoder_set_m_n(intel_crtc,
|
2015-01-15 14:55:25 +02:00
|
|
|
&intel_crtc->config->fdi_m_n, NULL);
|
2014-04-24 23:55:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ironlake_set_pipeconf(crtc);
|
|
|
|
|
|
2011-01-05 10:31:48 -08:00
|
|
|
intel_crtc->active = true;
|
drm/i915: report Gen5+ CPU and PCH FIFO underruns
In this commit we enable both CPU and PCH FIFO underrun reporting and
start reporting them. We follow a few rules:
- after we receive one of these errors, we mask the interrupt, so
we won't get an "interrupt storm" and we also won't flood dmesg;
- at each mode set we enable the interrupts again, so we'll see each
message at most once per mode set;
- in the specific places where we need to ignore the errors, we
completely mask the interrupts.
The downside of this patch is that since we're completely disabling
(masking) the interrupts instead of just not printing error messages,
we will mask more than just what we want on IVB/HSW CPU interrupts
(due to GEN7_ERR_INT) and on CPT/PPT/LPT PCHs (due to SERR_INT). So
when we decide to mask PCH FIFO underruns for pipe A on CPT, we'll
also be masking PCH FIFO underruns for pipe B, because both are
reported by SERR_INT, which has to be either completely enabled or
completely disabled (in othe words, there's no way to disable/enable
specific bits of GEN7_ERR_INT and SERR_INT).
V2: Rename some functions and variables, downgrade messages to
DRM_DEBUG_DRIVER and rebase.
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-04-12 17:57:57 -03:00
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_pre_enable(crtc, pipe_config, old_state);
|
2011-01-05 10:31:48 -08:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder) {
|
2012-10-27 15:50:28 +02:00
|
|
|
/* Note: FDI PLL enabling _must_ be done before we enable the
|
|
|
|
|
* cpu pipes, hence this is separate from all the other fdi/pch
|
|
|
|
|
* enabling. */
|
2012-08-12 19:27:14 +02:00
|
|
|
ironlake_fdi_pll_enable(intel_crtc);
|
2012-09-06 22:08:33 +02:00
|
|
|
} else {
|
|
|
|
|
assert_fdi_tx_disabled(dev_priv, pipe);
|
|
|
|
|
assert_fdi_rx_disabled(dev_priv, pipe);
|
|
|
|
|
}
|
2011-01-05 10:31:48 -08:00
|
|
|
|
2013-04-25 12:55:02 -07:00
|
|
|
ironlake_pfit_enable(intel_crtc);
|
2011-01-05 10:31:48 -08:00
|
|
|
|
2011-06-15 23:32:33 +02:00
|
|
|
/*
|
|
|
|
|
* On ILK+ LUT must be loaded before the pipe is running but with
|
|
|
|
|
* clocks enabled
|
|
|
|
|
*/
|
2016-03-30 17:16:34 +02:00
|
|
|
intel_color_load_luts(&pipe_config->base);
|
2011-06-15 23:32:33 +02:00
|
|
|
|
2016-02-29 22:10:33 +02:00
|
|
|
if (dev_priv->display.initial_watermarks != NULL)
|
2016-11-08 13:55:32 +01:00
|
|
|
dev_priv->display.initial_watermarks(old_intel_state, intel_crtc->config);
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_enable_pipe(pipe_config);
|
2011-01-05 10:31:48 -08:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder)
|
2017-03-02 14:58:53 +02:00
|
|
|
ironlake_pch_enable(pipe_config);
|
2010-09-10 10:57:18 -07:00
|
|
|
|
2015-01-07 13:54:39 +01:00
|
|
|
assert_vblank_disabled(crtc);
|
|
|
|
|
drm_crtc_vblank_on(crtc);
|
|
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_enable(crtc, pipe_config, old_state);
|
2012-07-02 00:16:19 +02:00
|
|
|
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv))
|
2013-05-03 11:49:50 +02:00
|
|
|
cpt_verify_modeset(dev, intel_crtc->pipe);
|
2015-10-30 19:20:27 +02:00
|
|
|
|
|
|
|
|
/* Must wait for vblank to avoid spurious PCH FIFO underruns */
|
|
|
|
|
if (intel_crtc->config->has_pch_encoder)
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, pipe);
|
2016-04-01 21:53:17 +03:00
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
2015-10-30 19:20:27 +02:00
|
|
|
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
|
2010-09-10 10:26:01 -07:00
|
|
|
}
|
|
|
|
|
|
2013-05-31 16:33:22 -03:00
|
|
|
/* IPS only exists on ULT machines and is tied to pipe A. */
|
|
|
|
|
static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
|
|
|
|
|
{
|
2016-10-13 11:02:58 +01:00
|
|
|
return HAS_IPS(to_i915(crtc->base.dev)) && crtc->pipe == PIPE_A;
|
2013-05-31 16:33:22 -03:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 10:55:57 +03:00
|
|
|
static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe, bool apply)
|
|
|
|
|
{
|
|
|
|
|
u32 val = I915_READ(CLKGATE_DIS_PSL(pipe));
|
|
|
|
|
u32 mask = DPF_GATING_DIS | DPF_RAM_GATING_DIS | DPFR_GATING_DIS;
|
|
|
|
|
|
|
|
|
|
if (apply)
|
|
|
|
|
val |= mask;
|
|
|
|
|
else
|
|
|
|
|
val &= ~mask;
|
|
|
|
|
|
|
|
|
|
I915_WRITE(CLKGATE_DIS_PSL(pipe), val);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-05 15:21:31 -02:00
|
|
|
static void icl_pipe_mbus_enable(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
enum pipe pipe = crtc->pipe;
|
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
|
|
val = MBUS_DBOX_BW_CREDIT(1) | MBUS_DBOX_A_CREDIT(2);
|
|
|
|
|
|
|
|
|
|
/* Program B credit equally to all pipes */
|
|
|
|
|
val |= MBUS_DBOX_B_CREDIT(24 / INTEL_INFO(dev_priv)->num_pipes);
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PIPE_MBUS_DBOX_CTL(pipe), val);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-09 17:04:01 +02:00
|
|
|
static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2012-10-23 18:29:51 -02:00
|
|
|
{
|
2016-08-09 17:04:01 +02:00
|
|
|
struct drm_crtc *crtc = pipe_config->base.crtc;
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2012-10-23 18:29:51 -02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2015-06-01 12:50:09 +02:00
|
|
|
int pipe = intel_crtc->pipe, hsw_workaround_pipe;
|
2016-03-18 17:05:42 +02:00
|
|
|
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
|
2016-11-08 13:55:32 +01:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_state);
|
2017-10-02 10:55:57 +03:00
|
|
|
bool psl_clkgate_wa;
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2015-06-01 12:49:52 +02:00
|
|
|
if (WARN_ON(intel_crtc->active))
|
2012-10-23 18:29:51 -02:00
|
|
|
return;
|
|
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
|
2016-06-13 16:44:35 +03:00
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
if (intel_crtc->config->shared_dpll)
|
2014-06-25 22:02:03 +03:00
|
|
|
intel_enable_shared_dpll(intel_crtc);
|
|
|
|
|
|
2016-06-22 21:57:04 +03:00
|
|
|
if (intel_crtc_has_dp_encoder(intel_crtc->config))
|
2015-02-13 15:32:59 +05:30
|
|
|
intel_dp_set_m_n(intel_crtc, M1_N1);
|
2014-04-24 23:55:09 +02:00
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2016-03-18 17:05:42 +02:00
|
|
|
intel_set_pipe_timings(intel_crtc);
|
|
|
|
|
|
2016-03-18 17:05:39 +02:00
|
|
|
intel_set_pipe_src_size(intel_crtc);
|
2014-04-24 23:55:09 +02:00
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
if (cpu_transcoder != TRANSCODER_EDP &&
|
|
|
|
|
!transcoder_is_dsi(cpu_transcoder)) {
|
|
|
|
|
I915_WRITE(PIPE_MULT(cpu_transcoder),
|
2015-01-15 14:55:25 +02:00
|
|
|
intel_crtc->config->pixel_multiplier - 1);
|
2014-09-30 10:30:22 -07:00
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder) {
|
2014-04-24 23:55:09 +02:00
|
|
|
intel_cpu_transcoder_set_m_n(intel_crtc,
|
2015-01-15 14:55:25 +02:00
|
|
|
&intel_crtc->config->fdi_m_n, NULL);
|
2014-04-24 23:55:09 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2016-03-18 17:05:42 +02:00
|
|
|
haswell_set_pipeconf(crtc);
|
|
|
|
|
|
2016-03-18 17:05:40 +02:00
|
|
|
haswell_set_pipemisc(crtc);
|
2014-04-24 23:55:09 +02:00
|
|
|
|
2016-03-30 17:16:34 +02:00
|
|
|
intel_color_set_csc(&pipe_config->base);
|
2014-04-24 23:55:09 +02:00
|
|
|
|
2012-10-23 18:29:51 -02:00
|
|
|
intel_crtc->active = true;
|
drm/i915: report Gen5+ CPU and PCH FIFO underruns
In this commit we enable both CPU and PCH FIFO underrun reporting and
start reporting them. We follow a few rules:
- after we receive one of these errors, we mask the interrupt, so
we won't get an "interrupt storm" and we also won't flood dmesg;
- at each mode set we enable the interrupts again, so we'll see each
message at most once per mode set;
- in the specific places where we need to ignore the errors, we
completely mask the interrupts.
The downside of this patch is that since we're completely disabling
(masking) the interrupts instead of just not printing error messages,
we will mask more than just what we want on IVB/HSW CPU interrupts
(due to GEN7_ERR_INT) and on CPT/PPT/LPT PCHs (due to SERR_INT). So
when we decide to mask PCH FIFO underruns for pipe A on CPT, we'll
also be masking PCH FIFO underruns for pipe B, because both are
reported by SERR_INT, which has to be either completely enabled or
completely disabled (in othe words, there's no way to disable/enable
specific bits of GEN7_ERR_INT and SERR_INT).
V2: Rename some functions and variables, downgrade messages to
DRM_DEBUG_DRIVER and rebase.
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-04-12 17:57:57 -03:00
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_pre_enable(crtc, pipe_config, old_state);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2017-03-02 14:58:56 +02:00
|
|
|
intel_ddi_enable_pipe_clock(pipe_config);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2017-10-02 10:55:57 +03:00
|
|
|
/* Display WA #1180: WaDisableScalarClockGating: glk, cnl */
|
|
|
|
|
psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
|
|
|
|
|
intel_crtc->config->pch_pfit.enabled;
|
|
|
|
|
if (psl_clkgate_wa)
|
|
|
|
|
glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true);
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2015-07-13 16:30:15 +02:00
|
|
|
skylake_pfit_enable(intel_crtc);
|
2015-01-21 17:19:54 -08:00
|
|
|
else
|
2015-09-02 15:19:26 -07:00
|
|
|
ironlake_pfit_enable(intel_crtc);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* On ILK+ LUT must be loaded before the pipe is running but with
|
|
|
|
|
* clocks enabled
|
|
|
|
|
*/
|
2016-03-30 17:16:34 +02:00
|
|
|
intel_color_load_luts(&pipe_config->base);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2017-03-02 14:58:56 +02:00
|
|
|
intel_ddi_set_pipe_settings(pipe_config);
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2017-03-02 14:58:56 +02:00
|
|
|
intel_ddi_enable_transcoder_func(pipe_config);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-02-29 22:10:33 +02:00
|
|
|
if (dev_priv->display.initial_watermarks != NULL)
|
2016-11-28 19:37:03 +02:00
|
|
|
dev_priv->display.initial_watermarks(old_intel_state, pipe_config);
|
2016-03-18 17:05:42 +02:00
|
|
|
|
2018-02-05 15:21:31 -02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 11)
|
|
|
|
|
icl_pipe_mbus_enable(intel_crtc);
|
|
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
/* XXX: Do the pipe assertions at the right place for BXT DSI. */
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_enable_pipe(pipe_config);
|
2013-05-31 16:33:22 -03:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder)
|
2017-03-02 14:58:53 +02:00
|
|
|
lpt_pch_enable(pipe_config);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-11-14 19:44:06 +02:00
|
|
|
if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST))
|
2017-03-02 14:58:56 +02:00
|
|
|
intel_ddi_set_vc_payload_alloc(pipe_config, true);
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2015-01-07 13:54:39 +01:00
|
|
|
assert_vblank_disabled(crtc);
|
|
|
|
|
drm_crtc_vblank_on(crtc);
|
|
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_enable(crtc, pipe_config, old_state);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2017-10-02 10:55:57 +03:00
|
|
|
if (psl_clkgate_wa) {
|
|
|
|
|
intel_wait_for_vblank(dev_priv, pipe);
|
|
|
|
|
glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, false);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-20 16:21:19 -03:00
|
|
|
/* If we change the relative order between pipe/planes enabling, we need
|
|
|
|
|
* to change the workaround. */
|
2015-06-01 12:50:09 +02:00
|
|
|
hsw_workaround_pipe = pipe_config->hsw_workaround_pipe;
|
2016-10-13 11:03:01 +01:00
|
|
|
if (IS_HASWELL(dev_priv) && hsw_workaround_pipe != INVALID_PIPE) {
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, hsw_workaround_pipe);
|
|
|
|
|
intel_wait_for_vblank(dev_priv, hsw_workaround_pipe);
|
2015-06-01 12:50:09 +02:00
|
|
|
}
|
2012-10-23 18:29:51 -02:00
|
|
|
}
|
|
|
|
|
|
2015-08-27 15:44:05 +02:00
|
|
|
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
|
2013-05-08 10:36:30 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-05-08 10:36:30 +02:00
|
|
|
int pipe = crtc->pipe;
|
|
|
|
|
|
|
|
|
|
/* To avoid upsetting the power well on haswell only disable the pfit if
|
|
|
|
|
* it's in use. The hw state code will make sure we get this right. */
|
2015-08-27 15:44:05 +02:00
|
|
|
if (force || crtc->config->pch_pfit.enabled) {
|
2013-05-08 10:36:30 +02:00
|
|
|
I915_WRITE(PF_CTL(pipe), 0);
|
|
|
|
|
I915_WRITE(PF_WIN_POS(pipe), 0);
|
|
|
|
|
I915_WRITE(PF_WIN_SZ(pipe), 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-09 17:04:01 +02:00
|
|
|
static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2010-09-10 10:26:01 -07:00
|
|
|
{
|
2016-08-09 17:04:01 +02:00
|
|
|
struct drm_crtc *crtc = old_crtc_state->base.crtc;
|
2010-09-10 10:26:01 -07:00
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2010-09-10 10:26:01 -07:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
2010-06-12 14:32:27 +08:00
|
|
|
|
2016-04-01 21:53:17 +03:00
|
|
|
/*
|
|
|
|
|
* Sometimes spurious CPU pipe underruns happen when the
|
|
|
|
|
* pipe is already disabled, but FDI RX/TX is still enabled.
|
|
|
|
|
* Happens at least with VGA+HDMI cloning. Suppress them.
|
|
|
|
|
*/
|
|
|
|
|
if (intel_crtc->config->has_pch_encoder) {
|
|
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
|
2015-10-30 19:20:27 +02:00
|
|
|
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
|
2016-04-01 21:53:17 +03:00
|
|
|
}
|
2015-10-30 19:20:27 +02:00
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_disable(crtc, old_crtc_state, old_state);
|
2012-07-10 10:42:52 +02:00
|
|
|
|
2015-01-07 13:54:39 +01:00
|
|
|
drm_crtc_vblank_off(crtc);
|
|
|
|
|
assert_vblank_disabled(crtc);
|
|
|
|
|
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_disable_pipe(old_crtc_state);
|
2009-07-24 01:00:32 +08:00
|
|
|
|
2015-08-27 15:44:05 +02:00
|
|
|
ironlake_pfit_disable(intel_crtc, false);
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2016-04-01 21:53:17 +03:00
|
|
|
if (intel_crtc->config->has_pch_encoder)
|
2015-05-05 17:17:38 +03:00
|
|
|
ironlake_fdi_disable(crtc);
|
|
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_post_disable(crtc, old_crtc_state, old_state);
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->has_pch_encoder) {
|
2013-06-05 13:34:04 +02:00
|
|
|
ironlake_disable_pch_transcoder(dev_priv, pipe);
|
2010-09-10 10:26:01 -07:00
|
|
|
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_CPT(dev_priv)) {
|
drm/i915: Type safe register read/write
Make I915_READ and I915_WRITE more type safe by wrapping the register
offset in a struct. This should eliminate most of the fumbles we've had
with misplaced parens.
This only takes care of normal mmio registers. We could extend the idea
to other register types and define each with its own struct. That way
you wouldn't be able to accidentally pass the wrong thing to a specific
register access function.
The gpio_reg setup is probably the ugliest thing left. But I figure I'd
just leave it for now, and wait for some divine inspiration to strike
before making it nice.
As for the generated code, it's actually a bit better sometimes. Eg.
looking at i915_irq_handler(), we can see the following change:
lea 0x70024(%rdx,%rax,1),%r9d
mov $0x1,%edx
- movslq %r9d,%r9
- mov %r9,%rsi
- mov %r9,-0x58(%rbp)
- callq *0xd8(%rbx)
+ mov %r9d,%esi
+ mov %r9d,-0x48(%rbp)
callq *0xd8(%rbx)
So previously gcc thought the register offset might be signed and
decided to sign extend it, just in case. The rest appears to be
mostly just minor shuffling of instructions.
v2: i915_mmio_reg_{offset,equal,valid}() helpers added
s/_REG/_MMIO/ in the register defines
mo more switch statements left to worry about
ring_emit stuff got sorted in a prep patch
cmd parser, lrc context and w/a batch buildup also in prep patch
vgpu stuff cleaned up and moved to a prep patch
all other unrelated changes split out
v3: Rebased due to BXT DSI/BLC, MOCS, etc.
v4: Rebased due to churn, s/i915_mmio_reg_t/i915_reg_t/
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1447853606-2751-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-18 15:33:26 +02:00
|
|
|
i915_reg_t reg;
|
|
|
|
|
u32 temp;
|
|
|
|
|
|
2013-06-05 13:34:04 +02:00
|
|
|
/* disable TRANS_DP_CTL */
|
|
|
|
|
reg = TRANS_DP_CTL(pipe);
|
|
|
|
|
temp = I915_READ(reg);
|
|
|
|
|
temp &= ~(TRANS_DP_OUTPUT_ENABLE |
|
|
|
|
|
TRANS_DP_PORT_SEL_MASK);
|
|
|
|
|
temp |= TRANS_DP_PORT_SEL_NONE;
|
|
|
|
|
I915_WRITE(reg, temp);
|
|
|
|
|
|
|
|
|
|
/* disable DPLL_SEL */
|
|
|
|
|
temp = I915_READ(PCH_DPLL_SEL);
|
2013-06-05 13:34:09 +02:00
|
|
|
temp &= ~(TRANS_DPLL_ENABLE(pipe) | TRANS_DPLLB_SEL(pipe));
|
2013-06-05 13:34:04 +02:00
|
|
|
I915_WRITE(PCH_DPLL_SEL, temp);
|
2011-02-07 12:26:52 -08:00
|
|
|
}
|
2010-04-08 09:43:27 +08:00
|
|
|
|
2013-06-05 13:34:04 +02:00
|
|
|
ironlake_fdi_pll_disable(intel_crtc);
|
|
|
|
|
}
|
2015-10-30 19:21:31 +02:00
|
|
|
|
2016-04-01 21:53:17 +03:00
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
2015-10-30 19:21:31 +02:00
|
|
|
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
|
2010-09-10 10:26:01 -07:00
|
|
|
}
|
2009-11-25 13:09:38 +08:00
|
|
|
|
2016-08-09 17:04:01 +02:00
|
|
|
static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2012-04-20 17:11:53 +01:00
|
|
|
{
|
2016-08-09 17:04:01 +02:00
|
|
|
struct drm_crtc *crtc = old_crtc_state->base.crtc;
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2012-04-20 17:11:53 +01:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2015-01-15 14:55:25 +02:00
|
|
|
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
|
2012-04-20 17:11:53 +01:00
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_disable(crtc, old_crtc_state, old_state);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2015-01-07 13:54:39 +01:00
|
|
|
drm_crtc_vblank_off(crtc);
|
|
|
|
|
assert_vblank_disabled(crtc);
|
|
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
/* XXX: Do the pipe assertions at the right place for BXT DSI. */
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_disable_pipe(old_crtc_state);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-11-14 19:44:06 +02:00
|
|
|
if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST))
|
2017-03-02 14:58:56 +02:00
|
|
|
intel_ddi_set_vc_payload_alloc(intel_crtc->config, false);
|
2014-08-18 21:27:34 +03:00
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2015-10-01 22:23:49 +05:30
|
|
|
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2015-07-13 16:30:15 +02:00
|
|
|
skylake_scaler_disable(intel_crtc);
|
2015-01-21 17:19:54 -08:00
|
|
|
else
|
2015-08-27 15:44:05 +02:00
|
|
|
ironlake_pfit_disable(intel_crtc, false);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(cpu_transcoder))
|
2017-03-02 14:58:56 +02:00
|
|
|
intel_ddi_disable_pipe_clock(intel_crtc->config);
|
2012-10-23 18:29:51 -02:00
|
|
|
|
2016-08-09 17:04:04 +02:00
|
|
|
intel_encoders_post_disable(crtc, old_crtc_state, old_state);
|
2012-10-23 18:29:51 -02:00
|
|
|
}
|
|
|
|
|
|
2013-04-25 12:55:01 -07:00
|
|
|
static void i9xx_pfit_enable(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-01-15 14:55:25 +02:00
|
|
|
struct intel_crtc_state *pipe_config = crtc->config;
|
2013-04-25 12:55:01 -07:00
|
|
|
|
2015-01-15 14:55:24 +02:00
|
|
|
if (!pipe_config->gmch_pfit.control)
|
2013-04-25 12:55:01 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
2013-05-28 12:05:54 +02:00
|
|
|
* The panel fitter should only be adjusted whilst the pipe is disabled,
|
|
|
|
|
* according to register description and PRM.
|
2013-04-25 12:55:01 -07:00
|
|
|
*/
|
2013-05-28 12:05:54 +02:00
|
|
|
WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
|
|
|
|
|
assert_pipe_disabled(dev_priv, crtc->pipe);
|
2013-04-25 12:55:01 -07:00
|
|
|
|
2013-04-25 12:55:02 -07:00
|
|
|
I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios);
|
|
|
|
|
I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control);
|
2013-04-25 22:52:18 +02:00
|
|
|
|
|
|
|
|
/* Border color in case we don't scale up to the full screen. Black by
|
|
|
|
|
* default, change to something else for debugging. */
|
|
|
|
|
I915_WRITE(BCLRPAT(crtc->pipe), 0);
|
2013-04-25 12:55:01 -07:00
|
|
|
}
|
|
|
|
|
|
2017-02-22 08:34:27 +02:00
|
|
|
enum intel_display_power_domain intel_port_to_power_domain(enum port port)
|
2014-06-05 13:22:59 +10:00
|
|
|
{
|
|
|
|
|
switch (port) {
|
|
|
|
|
case PORT_A:
|
2015-11-09 16:48:21 +01:00
|
|
|
return POWER_DOMAIN_PORT_DDI_A_LANES;
|
2014-06-05 13:22:59 +10:00
|
|
|
case PORT_B:
|
2015-11-09 16:48:21 +01:00
|
|
|
return POWER_DOMAIN_PORT_DDI_B_LANES;
|
2014-06-05 13:22:59 +10:00
|
|
|
case PORT_C:
|
2015-11-09 16:48:21 +01:00
|
|
|
return POWER_DOMAIN_PORT_DDI_C_LANES;
|
2014-06-05 13:22:59 +10:00
|
|
|
case PORT_D:
|
2015-11-09 16:48:21 +01:00
|
|
|
return POWER_DOMAIN_PORT_DDI_D_LANES;
|
2015-08-13 18:00:12 +08:00
|
|
|
case PORT_E:
|
2015-11-09 16:48:21 +01:00
|
|
|
return POWER_DOMAIN_PORT_DDI_E_LANES;
|
2018-01-29 15:22:22 -08:00
|
|
|
case PORT_F:
|
|
|
|
|
return POWER_DOMAIN_PORT_DDI_F_LANES;
|
2014-06-05 13:22:59 +10:00
|
|
|
default:
|
2015-11-18 15:57:25 +02:00
|
|
|
MISSING_CASE(port);
|
2014-06-05 13:22:59 +10:00
|
|
|
return POWER_DOMAIN_PORT_OTHER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 11:31:21 +02:00
|
|
|
static u64 get_crtc_power_domains(struct drm_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
2014-03-05 16:20:52 +02:00
|
|
|
{
|
2014-03-04 19:22:57 +02:00
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-12-15 15:29:43 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-02-10 13:49:36 +01:00
|
|
|
struct drm_encoder *encoder;
|
2014-03-04 19:22:57 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 mask;
|
2016-02-10 13:49:36 +01:00
|
|
|
enum transcoder transcoder = crtc_state->cpu_transcoder;
|
2014-03-05 16:20:52 +02:00
|
|
|
|
2016-02-10 13:49:36 +01:00
|
|
|
if (!crtc_state->base.active)
|
2015-07-13 16:30:27 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2018-01-09 14:20:40 +02:00
|
|
|
mask = BIT_ULL(POWER_DOMAIN_PIPE(pipe));
|
|
|
|
|
mask |= BIT_ULL(POWER_DOMAIN_TRANSCODER(transcoder));
|
2016-02-10 13:49:36 +01:00
|
|
|
if (crtc_state->pch_pfit.enabled ||
|
|
|
|
|
crtc_state->pch_pfit.force_thru)
|
2017-02-09 11:31:21 +02:00
|
|
|
mask |= BIT_ULL(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
|
2014-03-05 16:20:52 +02:00
|
|
|
|
2016-02-10 13:49:36 +01:00
|
|
|
drm_for_each_encoder_mask(encoder, dev, crtc_state->base.encoder_mask) {
|
|
|
|
|
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
|
|
|
|
|
2017-02-22 08:34:27 +02:00
|
|
|
mask |= BIT_ULL(intel_encoder->power_domain);
|
2016-02-10 13:49:36 +01:00
|
|
|
}
|
2014-03-04 19:22:57 +02:00
|
|
|
|
2016-12-15 15:29:43 +01:00
|
|
|
if (HAS_DDI(dev_priv) && crtc_state->has_audio)
|
2018-01-09 14:20:40 +02:00
|
|
|
mask |= BIT_ULL(POWER_DOMAIN_AUDIO);
|
2016-12-15 15:29:43 +01:00
|
|
|
|
2016-03-14 09:27:54 +01:00
|
|
|
if (crtc_state->shared_dpll)
|
2017-02-09 11:31:21 +02:00
|
|
|
mask |= BIT_ULL(POWER_DOMAIN_PLLS);
|
2016-03-14 09:27:54 +01:00
|
|
|
|
2014-03-05 16:20:52 +02:00
|
|
|
return mask;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-13 16:57:33 +02:00
|
|
|
static u64
|
2016-02-10 13:49:36 +01:00
|
|
|
modeset_get_crtc_power_domains(struct drm_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
2014-03-05 16:20:52 +02:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2015-07-13 16:30:27 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
enum intel_display_power_domain domain;
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 domains, new_domains, old_domains;
|
2014-03-05 16:20:52 +02:00
|
|
|
|
2015-07-13 16:30:27 +02:00
|
|
|
old_domains = intel_crtc->enabled_power_domains;
|
2016-02-10 13:49:36 +01:00
|
|
|
intel_crtc->enabled_power_domains = new_domains =
|
|
|
|
|
get_crtc_power_domains(crtc, crtc_state);
|
2014-03-05 16:20:52 +02:00
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
domains = new_domains & ~old_domains;
|
2015-07-13 16:30:27 +02:00
|
|
|
|
|
|
|
|
for_each_power_domain(domain, domains)
|
|
|
|
|
intel_display_power_get(dev_priv, domain);
|
|
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
return old_domains & ~new_domains;
|
2015-07-13 16:30:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 domains)
|
2015-07-13 16:30:27 +02:00
|
|
|
{
|
|
|
|
|
enum intel_display_power_domain domain;
|
|
|
|
|
|
|
|
|
|
for_each_power_domain(domain, domains)
|
|
|
|
|
intel_display_power_put(dev_priv, domain);
|
|
|
|
|
}
|
2014-03-05 16:20:52 +02:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2015-08-18 14:36:59 +03:00
|
|
|
{
|
2017-03-02 19:14:57 +02:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_state);
|
2017-02-07 20:33:05 +02:00
|
|
|
struct drm_crtc *crtc = pipe_config->base.crtc;
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
2015-08-18 14:36:59 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (WARN_ON(intel_crtc->active))
|
|
|
|
|
return;
|
2015-08-18 14:36:59 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (intel_crtc_has_dp_encoder(intel_crtc->config))
|
|
|
|
|
intel_dp_set_m_n(intel_crtc, M1_N1);
|
2016-05-13 23:41:27 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_set_pipe_timings(intel_crtc);
|
|
|
|
|
intel_set_pipe_src_size(intel_crtc);
|
2016-05-13 23:41:27 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-06-04 18:21:33 +01:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
I915_WRITE(CHV_BLEND(pipe), CHV_BLEND_LEGACY);
|
|
|
|
|
I915_WRITE(CHV_CANVAS(pipe), 0);
|
2015-06-04 18:21:33 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
i9xx_set_pipeconf(intel_crtc);
|
2015-06-04 18:21:33 +01:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_crtc->active = true;
|
2016-05-11 22:44:45 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
2016-05-13 23:41:38 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_pre_pll_enable(crtc, pipe_config, old_state);
|
2016-05-13 23:41:38 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (IS_CHERRYVIEW(dev_priv)) {
|
|
|
|
|
chv_prepare_pll(intel_crtc, intel_crtc->config);
|
|
|
|
|
chv_enable_pll(intel_crtc, intel_crtc->config);
|
|
|
|
|
} else {
|
|
|
|
|
vlv_prepare_pll(intel_crtc, intel_crtc->config);
|
|
|
|
|
vlv_enable_pll(intel_crtc, intel_crtc->config);
|
2016-05-13 23:41:38 +03:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_pre_enable(crtc, pipe_config, old_state);
|
2016-05-13 23:41:38 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
i9xx_pfit_enable(intel_crtc);
|
2016-12-02 10:23:54 +02:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_color_load_luts(&pipe_config->base);
|
2016-12-02 10:23:54 +02:00
|
|
|
|
2017-03-02 19:14:57 +02:00
|
|
|
dev_priv->display.initial_watermarks(old_intel_state,
|
|
|
|
|
pipe_config);
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_enable_pipe(pipe_config);
|
2017-02-07 20:33:05 +02:00
|
|
|
|
|
|
|
|
assert_vblank_disabled(crtc);
|
|
|
|
|
drm_crtc_vblank_on(crtc);
|
2016-12-02 10:23:54 +02:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_enable(crtc, pipe_config, old_state);
|
2016-12-02 10:23:54 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
|
2016-05-13 23:41:34 +03:00
|
|
|
{
|
2017-02-07 20:33:05 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-13 23:41:35 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
I915_WRITE(FP0(crtc->pipe), crtc->config->dpll_hw_state.fp0);
|
|
|
|
|
I915_WRITE(FP1(crtc->pipe), crtc->config->dpll_hw_state.fp1);
|
2016-05-13 23:41:34 +03:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2016-05-13 23:41:34 +03:00
|
|
|
{
|
2017-04-21 21:14:29 +03:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_state);
|
2017-02-07 20:33:05 +02:00
|
|
|
struct drm_crtc *crtc = pipe_config->base.crtc;
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
2016-05-13 23:41:34 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (WARN_ON(intel_crtc->active))
|
|
|
|
|
return;
|
2016-05-13 23:41:34 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
i9xx_set_pll_dividers(intel_crtc);
|
2016-05-13 23:41:34 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (intel_crtc_has_dp_encoder(intel_crtc->config))
|
|
|
|
|
intel_dp_set_m_n(intel_crtc, M1_N1);
|
2016-05-13 23:41:35 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_set_pipe_timings(intel_crtc);
|
|
|
|
|
intel_set_pipe_src_size(intel_crtc);
|
2016-05-13 23:41:34 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
i9xx_set_pipeconf(intel_crtc);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_crtc->active = true;
|
2016-05-13 23:41:38 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (!IS_GEN2(dev_priv))
|
|
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
|
2016-05-13 23:41:38 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_pre_enable(crtc, pipe_config, old_state);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-09-13 17:08:56 +03:00
|
|
|
i9xx_enable_pll(intel_crtc, pipe_config);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
i9xx_pfit_enable(intel_crtc);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_color_load_luts(&pipe_config->base);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-04-21 21:14:29 +03:00
|
|
|
if (dev_priv->display.initial_watermarks != NULL)
|
|
|
|
|
dev_priv->display.initial_watermarks(old_intel_state,
|
|
|
|
|
intel_crtc->config);
|
|
|
|
|
else
|
|
|
|
|
intel_update_watermarks(intel_crtc);
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_enable_pipe(pipe_config);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
assert_vblank_disabled(crtc);
|
|
|
|
|
drm_crtc_vblank_on(crtc);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_enable(crtc, pipe_config, old_state);
|
|
|
|
|
}
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static void i9xx_pfit_disable(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (!crtc->config->gmch_pfit.control)
|
2014-11-24 13:37:39 +05:30
|
|
|
return;
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
assert_pipe_disabled(dev_priv, crtc->pipe);
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n",
|
|
|
|
|
I915_READ(PFIT_CONTROL));
|
|
|
|
|
I915_WRITE(PFIT_CONTROL, 0);
|
2014-11-24 13:37:39 +05:30
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
struct drm_atomic_state *old_state)
|
2014-11-24 13:37:39 +05:30
|
|
|
{
|
2017-02-07 20:33:05 +02:00
|
|
|
struct drm_crtc *crtc = old_crtc_state->base.crtc;
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
2016-05-24 15:38:33 +03:00
|
|
|
|
|
|
|
|
/*
|
2017-02-07 20:33:05 +02:00
|
|
|
* On gen2 planes are double buffered but the pipe isn't, so we must
|
|
|
|
|
* wait for planes to fully turn off before disabling the pipe.
|
2016-05-24 15:38:33 +03:00
|
|
|
*/
|
2017-02-07 20:33:05 +02:00
|
|
|
if (IS_GEN2(dev_priv))
|
|
|
|
|
intel_wait_for_vblank(dev_priv, pipe);
|
2016-05-24 15:38:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_disable(crtc, old_crtc_state, old_state);
|
2016-05-24 15:38:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
drm_crtc_vblank_off(crtc);
|
|
|
|
|
assert_vblank_disabled(crtc);
|
2016-05-24 15:38:33 +03:00
|
|
|
|
2017-11-29 17:37:32 +02:00
|
|
|
intel_disable_pipe(old_crtc_state);
|
2016-05-24 15:38:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
i9xx_pfit_disable(intel_crtc);
|
2016-12-02 10:23:54 +02:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_post_disable(crtc, old_crtc_state, old_state);
|
2016-05-24 15:38:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (!intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DSI)) {
|
|
|
|
|
if (IS_CHERRYVIEW(dev_priv))
|
|
|
|
|
chv_disable_pll(dev_priv, pipe);
|
|
|
|
|
else if (IS_VALLEYVIEW(dev_priv))
|
|
|
|
|
vlv_disable_pll(dev_priv, pipe);
|
|
|
|
|
else
|
|
|
|
|
i9xx_disable_pll(intel_crtc);
|
|
|
|
|
}
|
2016-04-01 16:02:43 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_encoders_post_pll_disable(crtc, old_crtc_state, old_state);
|
2016-12-02 10:23:54 +02:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (!IS_GEN2(dev_priv))
|
|
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
|
2017-03-02 19:14:57 +02:00
|
|
|
|
|
|
|
|
if (!dev_priv->display.initial_watermarks)
|
|
|
|
|
intel_update_watermarks(intel_crtc);
|
2017-06-01 17:36:16 +03:00
|
|
|
|
|
|
|
|
/* clock the pipe down to 640x480@60 to potentially save power */
|
|
|
|
|
if (IS_I830(dev_priv))
|
|
|
|
|
i830_enable_pipe(dev_priv, pipe);
|
2014-11-24 13:37:39 +05:30
|
|
|
}
|
|
|
|
|
|
2017-06-01 17:36:14 +03:00
|
|
|
static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
2014-11-24 13:37:39 +05:30
|
|
|
{
|
2017-02-07 20:33:05 +02:00
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
|
|
|
|
enum intel_display_power_domain domain;
|
2017-11-17 21:19:09 +02:00
|
|
|
struct intel_plane *plane;
|
2017-02-13 16:57:33 +02:00
|
|
|
u64 domains;
|
2017-02-07 20:33:05 +02:00
|
|
|
struct drm_atomic_state *state;
|
|
|
|
|
struct intel_crtc_state *crtc_state;
|
|
|
|
|
int ret;
|
2014-11-24 13:37:39 +05:30
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (!intel_crtc->active)
|
|
|
|
|
return;
|
2016-05-13 23:41:23 +03:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
for_each_intel_plane_on_crtc(&dev_priv->drm, intel_crtc, plane) {
|
|
|
|
|
const struct intel_plane_state *plane_state =
|
|
|
|
|
to_intel_plane_state(plane->base.state);
|
2016-05-13 23:41:33 +03:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
if (plane_state->base.visible)
|
|
|
|
|
intel_plane_disable_noatomic(intel_crtc, plane);
|
2017-02-07 20:33:05 +02:00
|
|
|
}
|
drm/i915/skl: Deinit/init the display at suspend/resume
We need to re-init the display hardware when going out of suspend. This
includes:
- Hooking the PCH to the reset logic
- Restoring CDCDLK
- Enabling the DDB power
Among those, only the CDCDLK one is a bit tricky. There's some
complexity in that:
- DPLL0 (which is the source for CDCLK) has two VCOs, each with a set
of supported frequencies. As eDP also uses DPLL0 for its link rate,
once DPLL0 is on, we restrict the possible eDP link rates the chosen
VCO.
- CDCLK also limits the bandwidth available to push pixels.
So, as a first step, this commit restore what the BIOS set, until I can
do more testing.
In case that's of interest for the reviewer, I've unit tested the
function that derives the decimal frequency field:
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
static const struct dpll_freq {
unsigned int freq;
unsigned int decimal;
} freqs[] = {
{ .freq = 308570, .decimal = 0b01001100111},
{ .freq = 337500, .decimal = 0b01010100001},
{ .freq = 432000, .decimal = 0b01101011110},
{ .freq = 450000, .decimal = 0b01110000010},
{ .freq = 540000, .decimal = 0b10000110110},
{ .freq = 617140, .decimal = 0b10011010000},
{ .freq = 675000, .decimal = 0b10101000100},
};
static void intbits(unsigned int v)
{
int i;
for(i = 10; i >= 0; i--)
putchar('0' + ((v >> i) & 1));
}
static unsigned int freq_decimal(unsigned int freq /* in kHz */)
{
return (freq - 1000) / 500;
}
static void test_freq(const struct dpll_freq *entry)
{
unsigned int decimal = freq_decimal(entry->freq);
printf("freq: %d, expected: ", entry->freq);
intbits(entry->decimal);
printf(", got: ");
intbits(decimal);
putchar('\n');
assert(decimal == entry->decimal);
}
int main(int argc, char **argv)
{
int i;
for (i = 0; i < ARRAY_SIZE(freqs); i++)
test_freq(&freqs[i]);
return 0;
}
v2:
- Rebase on top of -nightly
- Use (freq - 1000) / 500 for the decimal frequency (Ville)
- Fix setting the enable bit of HSW_NDE_RSTWRN_OPT (Ville)
- Rename skl_display_{resume,suspend} to skl_{init,uninit}_cdclk to
be consistent with the BXT code (Ville)
- Store boot CDCLK in ddi_pll_init (Ville)
- Merge dev_priv's skl_boot_cdclk into cdclk_freq
- Use LCPLL_PLL_LOCK instead of (1 << 30) (Ville)
- Replace various '0' by SKL_DPLL0 to be a bit more explicit that
we're programming DPLL0
- Busy poll the PCU before doing the frequency change. It takes about
3/4 cycles, each separated by 10us, to get the ACK from the CPU
(Ville)
v3:
- Restore dev_priv->skl_boot_cdclk, leaving unification with
dev_priv->cdclk_freq for a later patch (Daniel, Ville)
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-05-21 16:37:48 +01:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
state = drm_atomic_state_alloc(crtc->dev);
|
|
|
|
|
if (!state) {
|
|
|
|
|
DRM_DEBUG_KMS("failed to disable [CRTC:%d:%s], out of memory",
|
|
|
|
|
crtc->base.id, crtc->name);
|
2016-05-24 15:38:32 +03:00
|
|
|
return;
|
2017-02-07 20:33:05 +02:00
|
|
|
}
|
2016-05-13 23:41:29 +03:00
|
|
|
|
2017-06-01 17:36:14 +03:00
|
|
|
state->acquire_ctx = ctx;
|
2016-05-13 23:41:24 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
/* Everything's already locked, -EDEADLK can't happen. */
|
|
|
|
|
crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
|
|
|
|
|
ret = drm_atomic_add_affected_connectors(state, crtc);
|
2016-05-13 23:41:29 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
WARN_ON(IS_ERR(crtc_state) || ret);
|
drm/i915/skl: Deinit/init the display at suspend/resume
We need to re-init the display hardware when going out of suspend. This
includes:
- Hooking the PCH to the reset logic
- Restoring CDCDLK
- Enabling the DDB power
Among those, only the CDCDLK one is a bit tricky. There's some
complexity in that:
- DPLL0 (which is the source for CDCLK) has two VCOs, each with a set
of supported frequencies. As eDP also uses DPLL0 for its link rate,
once DPLL0 is on, we restrict the possible eDP link rates the chosen
VCO.
- CDCLK also limits the bandwidth available to push pixels.
So, as a first step, this commit restore what the BIOS set, until I can
do more testing.
In case that's of interest for the reviewer, I've unit tested the
function that derives the decimal frequency field:
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
static const struct dpll_freq {
unsigned int freq;
unsigned int decimal;
} freqs[] = {
{ .freq = 308570, .decimal = 0b01001100111},
{ .freq = 337500, .decimal = 0b01010100001},
{ .freq = 432000, .decimal = 0b01101011110},
{ .freq = 450000, .decimal = 0b01110000010},
{ .freq = 540000, .decimal = 0b10000110110},
{ .freq = 617140, .decimal = 0b10011010000},
{ .freq = 675000, .decimal = 0b10101000100},
};
static void intbits(unsigned int v)
{
int i;
for(i = 10; i >= 0; i--)
putchar('0' + ((v >> i) & 1));
}
static unsigned int freq_decimal(unsigned int freq /* in kHz */)
{
return (freq - 1000) / 500;
}
static void test_freq(const struct dpll_freq *entry)
{
unsigned int decimal = freq_decimal(entry->freq);
printf("freq: %d, expected: ", entry->freq);
intbits(entry->decimal);
printf(", got: ");
intbits(decimal);
putchar('\n');
assert(decimal == entry->decimal);
}
int main(int argc, char **argv)
{
int i;
for (i = 0; i < ARRAY_SIZE(freqs); i++)
test_freq(&freqs[i]);
return 0;
}
v2:
- Rebase on top of -nightly
- Use (freq - 1000) / 500 for the decimal frequency (Ville)
- Fix setting the enable bit of HSW_NDE_RSTWRN_OPT (Ville)
- Rename skl_display_{resume,suspend} to skl_{init,uninit}_cdclk to
be consistent with the BXT code (Ville)
- Store boot CDCLK in ddi_pll_init (Ville)
- Merge dev_priv's skl_boot_cdclk into cdclk_freq
- Use LCPLL_PLL_LOCK instead of (1 << 30) (Ville)
- Replace various '0' by SKL_DPLL0 to be a bit more explicit that
we're programming DPLL0
- Busy poll the PCU before doing the frequency change. It takes about
3/4 cycles, each separated by 10us, to get the ACK from the CPU
(Ville)
v3:
- Restore dev_priv->skl_boot_cdclk, leaving unification with
dev_priv->cdclk_freq for a later patch (Daniel, Ville)
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-05-21 16:37:48 +01:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
dev_priv->display.crtc_disable(crtc_state, state);
|
2016-08-09 17:04:01 +02:00
|
|
|
|
2016-10-14 13:18:18 +01:00
|
|
|
drm_atomic_state_put(state);
|
2016-03-02 15:48:01 +01:00
|
|
|
|
2016-05-27 20:59:19 +03:00
|
|
|
DRM_DEBUG_KMS("[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n",
|
|
|
|
|
crtc->base.id, crtc->name);
|
2016-03-02 15:48:01 +01:00
|
|
|
|
|
|
|
|
WARN_ON(drm_atomic_set_mode_for_crtc(crtc->state, NULL) < 0);
|
|
|
|
|
crtc->state->active = false;
|
2015-09-24 15:53:06 -07:00
|
|
|
intel_crtc->active = false;
|
2016-03-02 15:48:01 +01:00
|
|
|
crtc->enabled = false;
|
|
|
|
|
crtc->state->connector_mask = 0;
|
|
|
|
|
crtc->state->encoder_mask = 0;
|
|
|
|
|
|
|
|
|
|
for_each_encoder_on_crtc(crtc->dev, crtc, encoder)
|
|
|
|
|
encoder->base.crtc = NULL;
|
|
|
|
|
|
2016-01-19 11:35:51 -02:00
|
|
|
intel_fbc_disable(intel_crtc);
|
2016-10-31 22:37:03 +02:00
|
|
|
intel_update_watermarks(intel_crtc);
|
2015-07-13 11:55:05 +02:00
|
|
|
intel_disable_shared_dpll(intel_crtc);
|
2015-06-12 11:15:39 +02:00
|
|
|
|
|
|
|
|
domains = intel_crtc->enabled_power_domains;
|
|
|
|
|
for_each_power_domain(domain, domains)
|
|
|
|
|
intel_display_power_put(dev_priv, domain);
|
|
|
|
|
intel_crtc->enabled_power_domains = 0;
|
2015-12-10 12:33:57 +01:00
|
|
|
|
|
|
|
|
dev_priv->active_crtcs &= ~(1 << intel_crtc->pipe);
|
2017-08-30 21:57:03 +03:00
|
|
|
dev_priv->min_cdclk[intel_crtc->pipe] = 0;
|
2017-10-24 12:52:14 +03:00
|
|
|
dev_priv->min_voltage_level[intel_crtc->pipe] = 0;
|
2015-06-12 11:15:39 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-01 12:49:47 +02:00
|
|
|
/*
|
|
|
|
|
* turn all crtc's off, but do not adjust state
|
|
|
|
|
* This has to be paired with a call to intel_modeset_setup_hw_state.
|
|
|
|
|
*/
|
2015-07-13 16:30:29 +02:00
|
|
|
int intel_display_suspend(struct drm_device *dev)
|
2012-04-20 17:11:53 +01:00
|
|
|
{
|
2016-02-16 10:06:14 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-07-13 16:30:29 +02:00
|
|
|
struct drm_atomic_state *state;
|
2016-02-16 10:06:14 +01:00
|
|
|
int ret;
|
2015-07-13 16:30:29 +02:00
|
|
|
|
2016-02-16 10:06:14 +01:00
|
|
|
state = drm_atomic_helper_suspend(dev);
|
|
|
|
|
ret = PTR_ERR_OR_ZERO(state);
|
2015-07-13 16:30:29 +02:00
|
|
|
if (ret)
|
|
|
|
|
DRM_ERROR("Suspending crtc's failed with %i\n", ret);
|
2016-02-16 10:06:14 +01:00
|
|
|
else
|
|
|
|
|
dev_priv->modeset_restore_state = state;
|
2015-07-13 16:30:29 +02:00
|
|
|
return ret;
|
2012-04-20 17:11:53 +01:00
|
|
|
}
|
|
|
|
|
|
2010-08-04 13:50:23 +01:00
|
|
|
void intel_encoder_destroy(struct drm_encoder *encoder)
|
2010-09-10 10:47:20 -07:00
|
|
|
{
|
2010-09-09 15:14:28 +01:00
|
|
|
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
2010-08-04 13:50:23 +01:00
|
|
|
|
|
|
|
|
drm_encoder_cleanup(encoder);
|
|
|
|
|
kfree(intel_encoder);
|
2010-09-10 10:47:20 -07:00
|
|
|
}
|
|
|
|
|
|
2012-07-02 21:54:27 +02:00
|
|
|
/* Cross check the actual hw state with our own modeset state tracking (and it's
|
|
|
|
|
* internal consistency). */
|
2017-05-11 10:28:43 +02:00
|
|
|
static void intel_connector_verify_state(struct drm_crtc_state *crtc_state,
|
|
|
|
|
struct drm_connector_state *conn_state)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2017-05-11 10:28:43 +02:00
|
|
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
2015-08-06 13:49:22 +02:00
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
|
|
|
|
connector->base.base.id,
|
|
|
|
|
connector->base.name);
|
|
|
|
|
|
2012-07-02 21:54:27 +02:00
|
|
|
if (connector->get_hw_state(connector)) {
|
2015-08-27 13:13:31 +02:00
|
|
|
struct intel_encoder *encoder = connector->encoder;
|
2012-07-02 21:54:27 +02:00
|
|
|
|
2017-05-11 10:28:43 +02:00
|
|
|
I915_STATE_WARN(!crtc_state,
|
2015-08-06 13:49:22 +02:00
|
|
|
"connector enabled without attached crtc\n");
|
2012-07-02 21:54:27 +02:00
|
|
|
|
2017-05-11 10:28:43 +02:00
|
|
|
if (!crtc_state)
|
2015-08-06 13:49:22 +02:00
|
|
|
return;
|
|
|
|
|
|
2017-05-11 10:28:43 +02:00
|
|
|
I915_STATE_WARN(!crtc_state->active,
|
2015-08-06 13:49:22 +02:00
|
|
|
"connector is active, but attached crtc isn't\n");
|
|
|
|
|
|
2015-08-27 13:13:31 +02:00
|
|
|
if (!encoder || encoder->type == INTEL_OUTPUT_DP_MST)
|
2015-08-06 13:49:22 +02:00
|
|
|
return;
|
|
|
|
|
|
2015-08-27 13:13:31 +02:00
|
|
|
I915_STATE_WARN(conn_state->best_encoder != &encoder->base,
|
2015-08-06 13:49:22 +02:00
|
|
|
"atomic encoder doesn't match attached encoder\n");
|
|
|
|
|
|
2015-08-27 13:13:31 +02:00
|
|
|
I915_STATE_WARN(conn_state->crtc != encoder->base.crtc,
|
2015-08-06 13:49:22 +02:00
|
|
|
"attached encoder crtc differs from connector crtc\n");
|
|
|
|
|
} else {
|
2017-05-11 10:28:43 +02:00
|
|
|
I915_STATE_WARN(crtc_state && crtc_state->active,
|
2015-08-05 12:37:06 +02:00
|
|
|
"attached crtc is active, but connector isn't\n");
|
2017-05-11 10:28:43 +02:00
|
|
|
I915_STATE_WARN(!crtc_state && conn_state->best_encoder,
|
2015-08-06 13:49:22 +02:00
|
|
|
"best encoder set without crtc!\n");
|
2012-07-02 21:54:27 +02:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2015-04-10 10:59:10 +03:00
|
|
|
int intel_connector_init(struct intel_connector *connector)
|
|
|
|
|
{
|
2017-05-01 15:37:57 +02:00
|
|
|
struct intel_digital_connector_state *conn_state;
|
2015-04-10 10:59:10 +03:00
|
|
|
|
2017-05-01 15:37:57 +02:00
|
|
|
/*
|
|
|
|
|
* Allocate enough memory to hold intel_digital_connector_state,
|
|
|
|
|
* This might be a few bytes too many, but for connectors that don't
|
|
|
|
|
* need it we'll free the state and allocate a smaller one on the first
|
|
|
|
|
* succesful commit anyway.
|
|
|
|
|
*/
|
|
|
|
|
conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
|
|
|
|
|
if (!conn_state)
|
2015-04-10 10:59:10 +03:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
2017-05-01 15:37:57 +02:00
|
|
|
__drm_atomic_helper_connector_reset(&connector->base,
|
|
|
|
|
&conn_state->base);
|
|
|
|
|
|
2015-04-10 10:59:10 +03:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct intel_connector *intel_connector_alloc(void)
|
|
|
|
|
{
|
|
|
|
|
struct intel_connector *connector;
|
|
|
|
|
|
|
|
|
|
connector = kzalloc(sizeof *connector, GFP_KERNEL);
|
|
|
|
|
if (!connector)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (intel_connector_init(connector) < 0) {
|
|
|
|
|
kfree(connector);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return connector;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-13 11:01:44 -07:00
|
|
|
/*
|
|
|
|
|
* Free the bits allocated by intel_connector_alloc.
|
|
|
|
|
* This should only be used after intel_connector_alloc has returned
|
|
|
|
|
* successfully, and before drm_connector_init returns successfully.
|
|
|
|
|
* Otherwise the destroy callbacks for the connector and the state should
|
|
|
|
|
* take care of proper cleanup/free
|
|
|
|
|
*/
|
|
|
|
|
void intel_connector_free(struct intel_connector *connector)
|
|
|
|
|
{
|
|
|
|
|
kfree(to_intel_digital_connector_state(connector->base.state));
|
|
|
|
|
kfree(connector);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-02 13:10:34 +02:00
|
|
|
/* Simple connector->get_hw_state implementation for encoders that support only
|
|
|
|
|
* one connector and no cloning and hence the encoder state determines the state
|
|
|
|
|
* of the connector. */
|
|
|
|
|
bool intel_connector_get_hw_state(struct intel_connector *connector)
|
2010-08-04 13:50:23 +01:00
|
|
|
{
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
enum pipe pipe = 0;
|
2012-07-02 13:10:34 +02:00
|
|
|
struct intel_encoder *encoder = connector->encoder;
|
2010-08-04 13:50:23 +01:00
|
|
|
|
2012-07-02 13:10:34 +02:00
|
|
|
return encoder->get_hw_state(encoder, &pipe);
|
2010-08-04 13:50:23 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-30 08:33:12 +03:00
|
|
|
static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
|
2015-03-11 18:52:31 +02:00
|
|
|
{
|
2015-03-30 08:33:12 +03:00
|
|
|
if (crtc_state->base.enable && crtc_state->has_pch_encoder)
|
|
|
|
|
return crtc_state->fdi_lanes;
|
2015-03-11 18:52:31 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 08:33:12 +03:00
|
|
|
static int ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-04-29 19:34:16 +02:00
|
|
|
{
|
2016-10-13 11:03:00 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-03-30 08:33:12 +03:00
|
|
|
struct drm_atomic_state *state = pipe_config->base.state;
|
|
|
|
|
struct intel_crtc *other_crtc;
|
|
|
|
|
struct intel_crtc_state *other_crtc_state;
|
|
|
|
|
|
2013-04-29 19:34:16 +02:00
|
|
|
DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n",
|
|
|
|
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
|
|
|
|
if (pipe_config->fdi_lanes > 4) {
|
|
|
|
|
DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n",
|
|
|
|
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
2015-03-30 08:33:12 +03:00
|
|
|
return -EINVAL;
|
2013-04-29 19:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:03:00 +01:00
|
|
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
|
2013-04-29 19:34:16 +02:00
|
|
|
if (pipe_config->fdi_lanes > 2) {
|
|
|
|
|
DRM_DEBUG_KMS("only 2 lanes on haswell, required: %i lanes\n",
|
|
|
|
|
pipe_config->fdi_lanes);
|
2015-03-30 08:33:12 +03:00
|
|
|
return -EINVAL;
|
2013-04-29 19:34:16 +02:00
|
|
|
} else {
|
2015-03-30 08:33:12 +03:00
|
|
|
return 0;
|
2013-04-29 19:34:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 11:30:45 +00:00
|
|
|
if (INTEL_INFO(dev_priv)->num_pipes == 2)
|
2015-03-30 08:33:12 +03:00
|
|
|
return 0;
|
2013-04-29 19:34:16 +02:00
|
|
|
|
|
|
|
|
/* Ivybridge 3 pipe is really complicated */
|
|
|
|
|
switch (pipe) {
|
|
|
|
|
case PIPE_A:
|
2015-03-30 08:33:12 +03:00
|
|
|
return 0;
|
2013-04-29 19:34:16 +02:00
|
|
|
case PIPE_B:
|
2015-03-30 08:33:12 +03:00
|
|
|
if (pipe_config->fdi_lanes <= 2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2016-10-31 22:37:09 +02:00
|
|
|
other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
|
2015-03-30 08:33:12 +03:00
|
|
|
other_crtc_state =
|
|
|
|
|
intel_atomic_get_crtc_state(state, other_crtc);
|
|
|
|
|
if (IS_ERR(other_crtc_state))
|
|
|
|
|
return PTR_ERR(other_crtc_state);
|
|
|
|
|
|
|
|
|
|
if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
|
2013-04-29 19:34:16 +02:00
|
|
|
DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
|
|
|
|
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
2015-03-30 08:33:12 +03:00
|
|
|
return -EINVAL;
|
2013-04-29 19:34:16 +02:00
|
|
|
}
|
2015-03-30 08:33:12 +03:00
|
|
|
return 0;
|
2013-04-29 19:34:16 +02:00
|
|
|
case PIPE_C:
|
2015-03-11 18:52:30 +02:00
|
|
|
if (pipe_config->fdi_lanes > 2) {
|
|
|
|
|
DRM_DEBUG_KMS("only 2 lanes on pipe %c: required %i lanes\n",
|
|
|
|
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
2015-03-30 08:33:12 +03:00
|
|
|
return -EINVAL;
|
2015-03-11 18:52:30 +02:00
|
|
|
}
|
2015-03-30 08:33:12 +03:00
|
|
|
|
2016-10-31 22:37:09 +02:00
|
|
|
other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
|
2015-03-30 08:33:12 +03:00
|
|
|
other_crtc_state =
|
|
|
|
|
intel_atomic_get_crtc_state(state, other_crtc);
|
|
|
|
|
if (IS_ERR(other_crtc_state))
|
|
|
|
|
return PTR_ERR(other_crtc_state);
|
|
|
|
|
|
|
|
|
|
if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
|
2013-04-29 19:34:16 +02:00
|
|
|
DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n");
|
2015-03-30 08:33:12 +03:00
|
|
|
return -EINVAL;
|
2013-04-29 19:34:16 +02:00
|
|
|
}
|
2015-03-30 08:33:12 +03:00
|
|
|
return 0;
|
2013-04-29 19:34:16 +02:00
|
|
|
default:
|
|
|
|
|
BUG();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
#define RETRY 1
|
|
|
|
|
static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-04-19 11:24:43 +02:00
|
|
|
{
|
2013-04-29 19:34:16 +02:00
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
2015-09-08 13:40:49 +03:00
|
|
|
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
2015-03-30 08:33:12 +03:00
|
|
|
int lane, link_bw, fdi_dotclock, ret;
|
|
|
|
|
bool needs_recompute = false;
|
2013-04-19 11:24:43 +02:00
|
|
|
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
retry:
|
2013-04-19 11:24:43 +02:00
|
|
|
/* FDI is a binary signal running at ~2.7GHz, encoding
|
|
|
|
|
* each output octet as 10 bits. The actual frequency
|
|
|
|
|
* is stored as a divider into a 100MHz clock, and the
|
|
|
|
|
* mode pixel clock is stored in units of 1KHz.
|
|
|
|
|
* Hence the bw of each lane in terms of the mode signal
|
|
|
|
|
* is:
|
|
|
|
|
*/
|
2016-02-17 21:41:10 +02:00
|
|
|
link_bw = intel_fdi_link_freq(to_i915(dev), pipe_config);
|
2013-04-19 11:24:43 +02:00
|
|
|
|
2013-09-25 16:45:37 +01:00
|
|
|
fdi_dotclock = adjusted_mode->crtc_clock;
|
2013-04-19 11:24:43 +02:00
|
|
|
|
drm/i915: clear up the fdi dotclock semantics for M/N computation
We currently mutliply the link_bw of the fdi link with the pixel
multiplier, which is wrong: The FDI link doesn't suddenly grow more
bandwidth. In reality the pixel mutliplication only happens in the PCH,
before the pixels are fed into the port.
But since we our code treats the uses the target clock after pixels
are doubled (tripled, ...) already, we need to correct this.
Semantically it's clearer to divide the target clock to get the fdi
dotclock instead of multiplying the bw, so do that instead.
Note that the target clock is already multiplied by the same factor,
so the division will never loose accuracy for the M/N computation.
The lane computation otoh used the wrong value, we also need to feed
the fdi dotclock to that.
Split out on a request from Paulo Zanoni.
v2: Also fix the lane computation, it used the target clock to compute
the bw requirements, not the fdi dotclock (i.e. adjusted with the
pixel multiplier). Since sdvo only uses the pixel multiplier for
low-res modes (with a dotclock below 100MHz) we wouldn't ever have
rejected a bogus mode, but just used an inefficient fdi config.
v3: Amend the commit message to explain better what the change for the
fdi lane config computation is all about. Requested by Paulo.
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-06-01 17:16:19 +02:00
|
|
|
lane = ironlake_get_lanes_required(fdi_dotclock, link_bw,
|
2013-04-19 11:24:43 +02:00
|
|
|
pipe_config->pipe_bpp);
|
|
|
|
|
|
|
|
|
|
pipe_config->fdi_lanes = lane;
|
|
|
|
|
|
drm/i915: clear up the fdi dotclock semantics for M/N computation
We currently mutliply the link_bw of the fdi link with the pixel
multiplier, which is wrong: The FDI link doesn't suddenly grow more
bandwidth. In reality the pixel mutliplication only happens in the PCH,
before the pixels are fed into the port.
But since we our code treats the uses the target clock after pixels
are doubled (tripled, ...) already, we need to correct this.
Semantically it's clearer to divide the target clock to get the fdi
dotclock instead of multiplying the bw, so do that instead.
Note that the target clock is already multiplied by the same factor,
so the division will never loose accuracy for the M/N computation.
The lane computation otoh used the wrong value, we also need to feed
the fdi dotclock to that.
Split out on a request from Paulo Zanoni.
v2: Also fix the lane computation, it used the target clock to compute
the bw requirements, not the fdi dotclock (i.e. adjusted with the
pixel multiplier). Since sdvo only uses the pixel multiplier for
low-res modes (with a dotclock below 100MHz) we wouldn't ever have
rejected a bogus mode, but just used an inefficient fdi config.
v3: Amend the commit message to explain better what the change for the
fdi lane config computation is all about. Requested by Paulo.
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-06-01 17:16:19 +02:00
|
|
|
intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
|
2017-05-18 14:10:25 +03:00
|
|
|
link_bw, &pipe_config->fdi_m_n, false);
|
2013-04-29 19:34:16 +02:00
|
|
|
|
2016-02-17 21:41:09 +02:00
|
|
|
ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
|
2015-03-30 08:33:12 +03:00
|
|
|
if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
pipe_config->pipe_bpp -= 2*3;
|
2017-02-07 20:33:05 +02:00
|
|
|
DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n",
|
|
|
|
|
pipe_config->pipe_bpp);
|
|
|
|
|
needs_recompute = true;
|
|
|
|
|
pipe_config->bw_constrained = true;
|
2013-07-26 08:35:42 +02:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
goto retry;
|
2013-07-26 08:35:42 +02:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (needs_recompute)
|
|
|
|
|
return RETRY;
|
2009-09-21 10:42:27 -07:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
return ret;
|
2009-09-21 10:42:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state)
|
2009-09-21 10:42:27 -07:00
|
|
|
{
|
2017-11-22 19:39:01 +01:00
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
|
|
|
|
|
/* IPS only exists on ULT machines and is tied to pipe A. */
|
|
|
|
|
if (!hsw_crtc_supports_ips(crtc))
|
2017-08-17 17:55:09 +03:00
|
|
|
return false;
|
|
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (!i915_modparams.enable_ips)
|
2017-02-07 20:33:05 +02:00
|
|
|
return false;
|
2009-09-21 10:42:27 -07:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (crtc_state->pipe_bpp > 24)
|
|
|
|
|
return false;
|
2015-05-22 11:22:31 +03:00
|
|
|
|
2015-05-22 11:22:32 +03:00
|
|
|
/*
|
2017-02-07 20:33:05 +02:00
|
|
|
* We compare against max which means we must take
|
|
|
|
|
* the increased cdclk requirement into account when
|
|
|
|
|
* calculating the new cdclk.
|
|
|
|
|
*
|
|
|
|
|
* Should measure whether using a lower cdclk w/o IPS
|
2009-09-21 10:42:27 -07:00
|
|
|
*/
|
2017-11-22 19:39:01 +01:00
|
|
|
if (IS_BROADWELL(dev_priv) &&
|
|
|
|
|
crtc_state->pixel_rate > dev_priv->max_cdclk_freq * 95 / 100)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
2009-09-21 10:42:27 -07:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
static bool hsw_compute_ips_config(struct intel_crtc_state *crtc_state)
|
2017-02-07 20:33:05 +02:00
|
|
|
{
|
2017-11-22 19:39:01 +01:00
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(crtc_state->base.crtc->dev);
|
|
|
|
|
struct intel_atomic_state *intel_state =
|
|
|
|
|
to_intel_atomic_state(crtc_state->base.state);
|
|
|
|
|
|
|
|
|
|
if (!hsw_crtc_state_ips_capable(crtc_state))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (crtc_state->ips_force_disable)
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-11-22 19:39:06 +01:00
|
|
|
/* IPS should be fine as long as at least one plane is enabled. */
|
|
|
|
|
if (!(crtc_state->active_planes & ~BIT(PLANE_CURSOR)))
|
2017-11-22 19:39:01 +01:00
|
|
|
return false;
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
/* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
|
|
|
|
|
if (IS_BROADWELL(dev_priv) &&
|
|
|
|
|
crtc_state->pixel_rate > intel_state->cdclk.logical.cdclk * 95 / 100)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
2015-05-22 11:22:33 +03:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
|
2015-05-22 11:22:33 +03:00
|
|
|
{
|
2017-02-07 20:33:05 +02:00
|
|
|
const struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
/* GDG double wide on either pipe, otherwise pipe A only */
|
2018-02-09 21:58:46 +00:00
|
|
|
return INTEL_GEN(dev_priv) < 4 &&
|
2017-02-07 20:33:05 +02:00
|
|
|
(crtc->pipe == PIPE_A || IS_I915G(dev_priv));
|
2015-05-22 11:22:33 +03:00
|
|
|
}
|
|
|
|
|
|
2017-01-20 20:22:05 +02:00
|
|
|
static uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
uint32_t pixel_rate;
|
|
|
|
|
|
|
|
|
|
pixel_rate = pipe_config->base.adjusted_mode.crtc_clock;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We only use IF-ID interlacing. If we ever use
|
|
|
|
|
* PF-ID we'll need to adjust the pixel_rate here.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (pipe_config->pch_pfit.enabled) {
|
|
|
|
|
uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
|
|
|
|
|
uint32_t pfit_size = pipe_config->pch_pfit.size;
|
|
|
|
|
|
|
|
|
|
pipe_w = pipe_config->pipe_src_w;
|
|
|
|
|
pipe_h = pipe_config->pipe_src_h;
|
|
|
|
|
|
|
|
|
|
pfit_w = (pfit_size >> 16) & 0xFFFF;
|
|
|
|
|
pfit_h = pfit_size & 0xFFFF;
|
|
|
|
|
if (pipe_w < pfit_w)
|
|
|
|
|
pipe_w = pfit_w;
|
|
|
|
|
if (pipe_h < pfit_h)
|
|
|
|
|
pipe_h = pfit_h;
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(!pfit_w || !pfit_h))
|
|
|
|
|
return pixel_rate;
|
|
|
|
|
|
|
|
|
|
pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h,
|
|
|
|
|
pfit_w * pfit_h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pixel_rate;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
|
2015-05-22 11:22:33 +03:00
|
|
|
{
|
2017-02-07 20:33:05 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv))
|
|
|
|
|
/* FIXME calculate proper pipe pixel rate for GMCH pfit */
|
|
|
|
|
crtc_state->pixel_rate =
|
|
|
|
|
crtc_state->base.adjusted_mode.crtc_clock;
|
|
|
|
|
else
|
|
|
|
|
crtc_state->pixel_rate =
|
|
|
|
|
ilk_pipe_pixel_rate(crtc_state);
|
|
|
|
|
}
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
static int intel_crtc_compute_config(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
|
|
|
|
int clock_limit = dev_priv->max_dotclk_freq;
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (INTEL_GEN(dev_priv) < 4) {
|
|
|
|
|
clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
/*
|
|
|
|
|
* Enable double wide mode when the dot clock
|
|
|
|
|
* is > 90% of the (display) core speed.
|
|
|
|
|
*/
|
|
|
|
|
if (intel_crtc_supports_double_wide(crtc) &&
|
|
|
|
|
adjusted_mode->crtc_clock > clock_limit) {
|
|
|
|
|
clock_limit = dev_priv->max_dotclk_freq;
|
|
|
|
|
pipe_config->double_wide = true;
|
|
|
|
|
}
|
2015-05-22 11:22:33 +03:00
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (adjusted_mode->crtc_clock > clock_limit) {
|
|
|
|
|
DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
|
|
|
|
|
adjusted_mode->crtc_clock, clock_limit,
|
|
|
|
|
yesno(pipe_config->double_wide));
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-07-21 20:55:07 +05:30
|
|
|
if (pipe_config->ycbcr420 && pipe_config->base.ctm) {
|
|
|
|
|
/*
|
|
|
|
|
* There is only one pipe CSC unit per pipe, and we need that
|
|
|
|
|
* for output conversion from RGB->YCBCR. So if CTM is already
|
|
|
|
|
* applied we can't support YCBCR420 output.
|
|
|
|
|
*/
|
|
|
|
|
DRM_DEBUG_KMS("YCBCR420 and CTM together are not possible\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
/*
|
|
|
|
|
* Pipe horizontal size must be even in:
|
|
|
|
|
* - DVO ganged mode
|
|
|
|
|
* - LVDS dual channel mode
|
|
|
|
|
* - Double wide pipe
|
|
|
|
|
*/
|
|
|
|
|
if ((intel_crtc_has_type(pipe_config, INTEL_OUTPUT_LVDS) &&
|
|
|
|
|
intel_is_dual_link_lvds(dev)) || pipe_config->double_wide)
|
|
|
|
|
pipe_config->pipe_src_w &= ~1;
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
/* Cantiga+ cannot handle modes with a hsync front porch of 0.
|
|
|
|
|
* WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
|
|
|
|
|
*/
|
|
|
|
|
if ((INTEL_GEN(dev_priv) > 4 || IS_G4X(dev_priv)) &&
|
|
|
|
|
adjusted_mode->crtc_hsync_start == adjusted_mode->crtc_hdisplay)
|
|
|
|
|
return -EINVAL;
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_crtc_compute_pixel_rate(pipe_config);
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
if (pipe_config->has_pch_encoder)
|
|
|
|
|
return ironlake_fdi_compute_config(crtc, pipe_config);
|
2015-05-22 11:22:33 +03:00
|
|
|
|
2017-02-07 20:33:05 +02:00
|
|
|
return 0;
|
2015-05-22 11:22:33 +03:00
|
|
|
}
|
|
|
|
|
|
2009-06-05 15:38:42 +08:00
|
|
|
static void
|
2013-04-23 15:03:34 +03:00
|
|
|
intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den)
|
2009-06-05 15:38:42 +08:00
|
|
|
{
|
2013-04-23 15:03:34 +03:00
|
|
|
while (*num > DATA_LINK_M_N_MASK ||
|
|
|
|
|
*den > DATA_LINK_M_N_MASK) {
|
2009-06-05 15:38:42 +08:00
|
|
|
*num >>= 1;
|
|
|
|
|
*den >>= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-23 15:03:34 +03:00
|
|
|
static void compute_m_n(unsigned int m, unsigned int n,
|
2017-05-18 14:10:25 +03:00
|
|
|
uint32_t *ret_m, uint32_t *ret_n,
|
|
|
|
|
bool reduce_m_n)
|
2013-04-23 15:03:34 +03:00
|
|
|
{
|
2017-03-27 14:33:25 +03:00
|
|
|
/*
|
|
|
|
|
* Reduce M/N as much as possible without loss in precision. Several DP
|
|
|
|
|
* dongles in particular seem to be fussy about too large *link* M/N
|
|
|
|
|
* values. The passed in values are more likely to have the least
|
|
|
|
|
* significant bits zero than M after rounding below, so do this first.
|
|
|
|
|
*/
|
2017-05-18 14:10:25 +03:00
|
|
|
if (reduce_m_n) {
|
|
|
|
|
while ((m & 1) == 0 && (n & 1) == 0) {
|
|
|
|
|
m >>= 1;
|
|
|
|
|
n >>= 1;
|
|
|
|
|
}
|
2017-03-27 14:33:25 +03:00
|
|
|
}
|
|
|
|
|
|
2013-04-23 15:03:34 +03:00
|
|
|
*ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
|
|
|
|
|
*ret_m = div_u64((uint64_t) m * *ret_n, n);
|
|
|
|
|
intel_reduce_m_n_ratio(ret_m, ret_n);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-29 15:59:36 +01:00
|
|
|
void
|
|
|
|
|
intel_link_compute_m_n(int bits_per_pixel, int nlanes,
|
|
|
|
|
int pixel_clock, int link_clock,
|
2017-05-18 14:10:25 +03:00
|
|
|
struct intel_link_m_n *m_n,
|
|
|
|
|
bool reduce_m_n)
|
2009-06-05 15:38:42 +08:00
|
|
|
{
|
2012-11-29 15:59:36 +01:00
|
|
|
m_n->tu = 64;
|
2013-04-23 15:03:34 +03:00
|
|
|
|
|
|
|
|
compute_m_n(bits_per_pixel * pixel_clock,
|
|
|
|
|
link_clock * nlanes * 8,
|
2017-05-18 14:10:25 +03:00
|
|
|
&m_n->gmch_m, &m_n->gmch_n,
|
|
|
|
|
reduce_m_n);
|
2013-04-23 15:03:34 +03:00
|
|
|
|
|
|
|
|
compute_m_n(pixel_clock, link_clock,
|
2017-05-18 14:10:25 +03:00
|
|
|
&m_n->link_m, &m_n->link_n,
|
|
|
|
|
reduce_m_n);
|
2009-06-05 15:38:42 +08:00
|
|
|
}
|
|
|
|
|
|
2011-01-12 17:04:08 +00:00
|
|
|
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
2017-09-19 19:38:44 +00:00
|
|
|
if (i915_modparams.panel_use_ssc >= 0)
|
|
|
|
|
return i915_modparams.panel_use_ssc != 0;
|
2013-05-09 20:03:18 -03:00
|
|
|
return dev_priv->vbt.lvds_use_ssc
|
2011-07-12 14:56:22 -07:00
|
|
|
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
|
2011-01-12 17:04:08 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-20 17:19:46 +02:00
|
|
|
static uint32_t pnv_dpll_compute_fp(struct dpll *dpll)
|
2011-12-15 12:30:36 -08:00
|
|
|
{
|
2013-05-21 21:54:55 +02:00
|
|
|
return (1 << dpll->n) << 16 | dpll->m2;
|
2013-04-20 17:19:46 +02:00
|
|
|
}
|
2013-03-28 10:42:02 +01:00
|
|
|
|
2013-04-20 17:19:46 +02:00
|
|
|
static uint32_t i9xx_dpll_compute_fp(struct dpll *dpll)
|
|
|
|
|
{
|
|
|
|
|
return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
|
2011-12-15 12:30:36 -08:00
|
|
|
}
|
|
|
|
|
|
2013-03-28 10:42:02 +01:00
|
|
|
static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
|
2015-01-15 14:55:23 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll *reduced_clock)
|
2011-12-15 12:30:37 -08:00
|
|
|
{
|
2016-10-31 22:37:15 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2011-12-15 12:30:37 -08:00
|
|
|
u32 fp, fp2 = 0;
|
|
|
|
|
|
2016-10-31 22:37:15 +02:00
|
|
|
if (IS_PINEVIEW(dev_priv)) {
|
2015-01-15 14:55:23 +02:00
|
|
|
fp = pnv_dpll_compute_fp(&crtc_state->dpll);
|
2011-12-15 12:30:37 -08:00
|
|
|
if (reduced_clock)
|
2013-04-20 17:19:46 +02:00
|
|
|
fp2 = pnv_dpll_compute_fp(reduced_clock);
|
2011-12-15 12:30:37 -08:00
|
|
|
} else {
|
2015-01-15 14:55:23 +02:00
|
|
|
fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
|
2011-12-15 12:30:37 -08:00
|
|
|
if (reduced_clock)
|
2013-04-20 17:19:46 +02:00
|
|
|
fp2 = i9xx_dpll_compute_fp(reduced_clock);
|
2011-12-15 12:30:37 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
crtc_state->dpll_hw_state.fp0 = fp;
|
2011-12-15 12:30:37 -08:00
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
|
2015-03-24 12:40:09 -07:00
|
|
|
reduced_clock) {
|
2015-01-15 14:55:23 +02:00
|
|
|
crtc_state->dpll_hw_state.fp1 = fp2;
|
2011-12-15 12:30:37 -08:00
|
|
|
} else {
|
2015-01-15 14:55:23 +02:00
|
|
|
crtc_state->dpll_hw_state.fp1 = fp;
|
2011-12-15 12:30:37 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 20:41:49 +08:00
|
|
|
static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
|
|
|
|
|
pipe)
|
2013-04-18 14:51:36 -07:00
|
|
|
{
|
|
|
|
|
u32 reg_val;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* PLLB opamp always calibrates to max value of 0x3f, force enable it
|
|
|
|
|
* and set it to a reasonable value instead.
|
|
|
|
|
*/
|
2013-11-07 10:43:30 +08:00
|
|
|
reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1));
|
2013-04-18 14:51:36 -07:00
|
|
|
reg_val &= 0xffffff00;
|
|
|
|
|
reg_val |= 0x00000030;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
2013-11-07 10:43:30 +08:00
|
|
|
reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13);
|
2017-05-10 12:21:47 +03:00
|
|
|
reg_val &= 0x00ffffff;
|
|
|
|
|
reg_val |= 0x8c000000;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
2013-11-07 10:43:30 +08:00
|
|
|
reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1));
|
2013-04-18 14:51:36 -07:00
|
|
|
reg_val &= 0xffffff00;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
2013-11-07 10:43:30 +08:00
|
|
|
reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13);
|
2013-04-18 14:51:36 -07:00
|
|
|
reg_val &= 0x00ffffff;
|
|
|
|
|
reg_val |= 0xb0000000;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
|
2013-04-18 14:51:36 -07:00
|
|
|
}
|
|
|
|
|
|
2013-05-03 11:49:48 +02:00
|
|
|
static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_link_m_n *m_n)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-05-03 11:49:48 +02:00
|
|
|
int pipe = crtc->pipe;
|
|
|
|
|
|
2013-05-03 11:49:49 +02:00
|
|
|
I915_WRITE(PCH_TRANS_DATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
|
|
|
|
|
I915_WRITE(PCH_TRANS_DATA_N1(pipe), m_n->gmch_n);
|
|
|
|
|
I915_WRITE(PCH_TRANS_LINK_M1(pipe), m_n->link_m);
|
|
|
|
|
I915_WRITE(PCH_TRANS_LINK_N1(pipe), m_n->link_n);
|
2013-05-03 11:49:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
|
2014-08-05 07:51:22 -07:00
|
|
|
struct intel_link_m_n *m_n,
|
|
|
|
|
struct intel_link_m_n *m2_n2)
|
2013-05-03 11:49:48 +02:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2013-05-03 11:49:48 +02:00
|
|
|
int pipe = crtc->pipe;
|
2015-01-15 14:55:25 +02:00
|
|
|
enum transcoder transcoder = crtc->config->cpu_transcoder;
|
2013-05-03 11:49:48 +02:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 5) {
|
2013-05-03 11:49:48 +02:00
|
|
|
I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
|
|
|
|
|
I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
|
|
|
|
|
I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
|
|
|
|
|
I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
|
2014-08-05 07:51:22 -07:00
|
|
|
/* M2_N2 registers to be set only for gen < 8 (M2_N2 available
|
|
|
|
|
* for gen < 8) and if DRRS is supported (to make sure the
|
|
|
|
|
* registers are not unnecessarily accessed).
|
|
|
|
|
*/
|
2016-10-14 10:13:44 +01:00
|
|
|
if (m2_n2 && (IS_CHERRYVIEW(dev_priv) ||
|
|
|
|
|
INTEL_GEN(dev_priv) < 8) && crtc->config->has_drrs) {
|
2014-08-05 07:51:22 -07:00
|
|
|
I915_WRITE(PIPE_DATA_M2(transcoder),
|
|
|
|
|
TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
|
|
|
|
|
I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n);
|
|
|
|
|
I915_WRITE(PIPE_LINK_M2(transcoder), m2_n2->link_m);
|
|
|
|
|
I915_WRITE(PIPE_LINK_N2(transcoder), m2_n2->link_n);
|
|
|
|
|
}
|
2013-05-03 11:49:48 +02:00
|
|
|
} else {
|
2013-05-03 11:49:49 +02:00
|
|
|
I915_WRITE(PIPE_DATA_M_G4X(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
|
|
|
|
|
I915_WRITE(PIPE_DATA_N_G4X(pipe), m_n->gmch_n);
|
|
|
|
|
I915_WRITE(PIPE_LINK_M_G4X(pipe), m_n->link_m);
|
|
|
|
|
I915_WRITE(PIPE_LINK_N_G4X(pipe), m_n->link_n);
|
2013-05-03 11:49:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 15:32:59 +05:30
|
|
|
void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n)
|
2013-04-02 23:42:31 +02:00
|
|
|
{
|
2015-02-13 15:32:59 +05:30
|
|
|
struct intel_link_m_n *dp_m_n, *dp_m2_n2 = NULL;
|
|
|
|
|
|
|
|
|
|
if (m_n == M1_N1) {
|
|
|
|
|
dp_m_n = &crtc->config->dp_m_n;
|
|
|
|
|
dp_m2_n2 = &crtc->config->dp_m2_n2;
|
|
|
|
|
} else if (m_n == M2_N2) {
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* M2_N2 registers are not supported. Hence m2_n2 divider value
|
|
|
|
|
* needs to be programmed into M1_N1.
|
|
|
|
|
*/
|
|
|
|
|
dp_m_n = &crtc->config->dp_m2_n2;
|
|
|
|
|
} else {
|
|
|
|
|
DRM_ERROR("Unsupported divider value\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (crtc->config->has_pch_encoder)
|
|
|
|
|
intel_pch_transcoder_set_m_n(crtc, &crtc->config->dp_m_n);
|
2013-04-02 23:42:31 +02:00
|
|
|
else
|
2015-02-13 15:32:59 +05:30
|
|
|
intel_cpu_transcoder_set_m_n(crtc, dp_m_n, dp_m2_n2);
|
2013-04-02 23:42:31 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-18 10:30:24 +02:00
|
|
|
static void vlv_compute_dpll(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-04-24 23:55:11 +02:00
|
|
|
{
|
2016-03-15 16:39:55 +02:00
|
|
|
pipe_config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
|
2016-04-12 22:14:34 +03:00
|
|
|
DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
|
2016-03-15 16:39:55 +02:00
|
|
|
if (crtc->pipe != PIPE_A)
|
|
|
|
|
pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
|
2014-04-24 23:55:11 +02:00
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
/* DPLL not used with DSI, but still need the rest set up */
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
|
2016-04-12 22:14:34 +03:00
|
|
|
pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
|
|
|
|
|
DPLL_EXT_BUFFER_ENABLE_VLV;
|
|
|
|
|
|
2016-03-15 16:39:55 +02:00
|
|
|
pipe_config->dpll_hw_state.dpll_md =
|
|
|
|
|
(pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
|
|
|
|
|
}
|
2014-04-24 23:55:11 +02:00
|
|
|
|
2016-03-15 16:39:55 +02:00
|
|
|
static void chv_compute_dpll(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
|
2016-04-12 22:14:34 +03:00
|
|
|
DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
|
2016-03-15 16:39:55 +02:00
|
|
|
if (crtc->pipe != PIPE_A)
|
|
|
|
|
pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
|
|
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
/* DPLL not used with DSI, but still need the rest set up */
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
|
2016-04-12 22:14:34 +03:00
|
|
|
pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
|
|
|
|
|
|
2016-03-15 16:39:55 +02:00
|
|
|
pipe_config->dpll_hw_state.dpll_md =
|
|
|
|
|
(pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
|
2014-04-24 23:55:11 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 13:20:22 +02:00
|
|
|
static void vlv_prepare_pll(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
const struct intel_crtc_state *pipe_config)
|
2012-06-15 11:55:13 -07:00
|
|
|
{
|
2013-03-28 10:42:02 +01:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-04-12 22:14:34 +03:00
|
|
|
enum pipe pipe = crtc->pipe;
|
2014-04-24 23:55:11 +02:00
|
|
|
u32 mdiv;
|
2012-06-15 11:55:13 -07:00
|
|
|
u32 bestn, bestm1, bestm2, bestp1, bestp2;
|
2014-04-24 23:55:11 +02:00
|
|
|
u32 coreclk, reg_val;
|
2012-06-15 11:55:13 -07:00
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
/* Enable Refclk */
|
|
|
|
|
I915_WRITE(DPLL(pipe),
|
|
|
|
|
pipe_config->dpll_hw_state.dpll &
|
|
|
|
|
~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV));
|
|
|
|
|
|
|
|
|
|
/* No need to actually set up the DPLL with DSI */
|
|
|
|
|
if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2012-12-12 14:06:44 +01:00
|
|
|
|
2014-10-28 13:20:22 +02:00
|
|
|
bestn = pipe_config->dpll.n;
|
|
|
|
|
bestm1 = pipe_config->dpll.m1;
|
|
|
|
|
bestm2 = pipe_config->dpll.m2;
|
|
|
|
|
bestp1 = pipe_config->dpll.p1;
|
|
|
|
|
bestp2 = pipe_config->dpll.p2;
|
2012-06-15 11:55:13 -07:00
|
|
|
|
2013-04-18 14:51:36 -07:00
|
|
|
/* See eDP HDMI DPIO driver vbios notes doc */
|
|
|
|
|
|
|
|
|
|
/* PLL B needs special handling */
|
2014-04-24 23:55:11 +02:00
|
|
|
if (pipe == PIPE_B)
|
2013-09-05 20:41:49 +08:00
|
|
|
vlv_pllb_recal_opamp(dev_priv, pipe);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
|
|
|
|
/* Set up Tx target for periodic Rcomp update */
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
|
|
|
|
/* Disable target IRef on PLL */
|
2013-11-07 10:43:30 +08:00
|
|
|
reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe));
|
2013-04-18 14:51:36 -07:00
|
|
|
reg_val &= 0x00ffffff;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
|
|
|
|
/* Disable fast lock */
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610);
|
2013-04-18 14:51:36 -07:00
|
|
|
|
|
|
|
|
/* Set idtafcrecal before PLL is enabled */
|
2012-06-15 11:55:13 -07:00
|
|
|
mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
|
|
|
|
|
mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT));
|
|
|
|
|
mdiv |= ((bestn << DPIO_N_SHIFT));
|
|
|
|
|
mdiv |= (1 << DPIO_K_SHIFT);
|
2013-05-02 10:48:09 -07:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Post divider depends on pixel clock rate, DAC vs digital (and LVDS,
|
|
|
|
|
* but we don't support that).
|
|
|
|
|
* Note: don't use the DAC post divider as it seems unstable.
|
|
|
|
|
*/
|
|
|
|
|
mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT);
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv);
|
2012-06-15 11:55:13 -07:00
|
|
|
|
|
|
|
|
mdiv |= DPIO_ENABLE_CALIBRATION;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv);
|
2012-06-15 11:55:13 -07:00
|
|
|
|
2013-04-18 14:51:36 -07:00
|
|
|
/* Set HBR and RBR LPF coefficients */
|
2014-10-28 13:20:22 +02:00
|
|
|
if (pipe_config->port_clock == 162000 ||
|
2016-06-22 21:57:02 +03:00
|
|
|
intel_crtc_has_type(crtc->config, INTEL_OUTPUT_ANALOG) ||
|
|
|
|
|
intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI))
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
|
2013-07-05 19:21:38 +03:00
|
|
|
0x009f0003);
|
2013-04-18 14:51:36 -07:00
|
|
|
else
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
|
2013-04-18 14:51:36 -07:00
|
|
|
0x00d0000f);
|
|
|
|
|
|
2016-06-22 21:57:04 +03:00
|
|
|
if (intel_crtc_has_dp_encoder(pipe_config)) {
|
2013-04-18 14:51:36 -07:00
|
|
|
/* Use SSC source */
|
2014-04-24 23:55:11 +02:00
|
|
|
if (pipe == PIPE_A)
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
|
2013-04-18 14:51:36 -07:00
|
|
|
0x0df40000);
|
|
|
|
|
else
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
|
2013-04-18 14:51:36 -07:00
|
|
|
0x0df70000);
|
|
|
|
|
} else { /* HDMI or VGA */
|
|
|
|
|
/* Use bend source */
|
2014-04-24 23:55:11 +02:00
|
|
|
if (pipe == PIPE_A)
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
|
2013-04-18 14:51:36 -07:00
|
|
|
0x0df70000);
|
|
|
|
|
else
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
|
2013-04-18 14:51:36 -07:00
|
|
|
0x0df40000);
|
|
|
|
|
}
|
2012-06-15 11:55:13 -07:00
|
|
|
|
2013-11-07 10:43:30 +08:00
|
|
|
coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe));
|
2013-04-18 14:51:36 -07:00
|
|
|
coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
|
2016-06-22 21:57:05 +03:00
|
|
|
if (intel_crtc_has_dp_encoder(crtc->config))
|
2013-04-18 14:51:36 -07:00
|
|
|
coreclk |= 0x01000000;
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
|
2012-06-15 11:55:13 -07:00
|
|
|
|
2013-11-07 10:43:30 +08:00
|
|
|
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000);
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2012-06-15 11:55:13 -07:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 13:20:22 +02:00
|
|
|
static void chv_prepare_pll(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
const struct intel_crtc_state *pipe_config)
|
2014-05-02 14:27:47 +03:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-04-12 22:14:34 +03:00
|
|
|
enum pipe pipe = crtc->pipe;
|
2014-05-02 14:27:47 +03:00
|
|
|
enum dpio_channel port = vlv_pipe_to_channel(pipe);
|
2015-03-05 19:33:08 +05:30
|
|
|
u32 loopfilter, tribuf_calcntr;
|
2014-05-02 14:27:47 +03:00
|
|
|
u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
|
2015-03-05 19:30:57 +05:30
|
|
|
u32 dpio_val;
|
2015-03-05 19:33:08 +05:30
|
|
|
int vco;
|
2014-05-02 14:27:47 +03:00
|
|
|
|
2016-04-12 22:14:34 +03:00
|
|
|
/* Enable Refclk and SSC */
|
|
|
|
|
I915_WRITE(DPLL(pipe),
|
|
|
|
|
pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);
|
|
|
|
|
|
|
|
|
|
/* No need to actually set up the DPLL with DSI */
|
|
|
|
|
if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2014-10-28 13:20:22 +02:00
|
|
|
bestn = pipe_config->dpll.n;
|
|
|
|
|
bestm2_frac = pipe_config->dpll.m2 & 0x3fffff;
|
|
|
|
|
bestm1 = pipe_config->dpll.m1;
|
|
|
|
|
bestm2 = pipe_config->dpll.m2 >> 22;
|
|
|
|
|
bestp1 = pipe_config->dpll.p1;
|
|
|
|
|
bestp2 = pipe_config->dpll.p2;
|
2015-03-05 19:33:08 +05:30
|
|
|
vco = pipe_config->dpll.vco;
|
2015-03-05 19:30:57 +05:30
|
|
|
dpio_val = 0;
|
2015-03-05 19:33:08 +05:30
|
|
|
loopfilter = 0;
|
2014-05-02 14:27:47 +03:00
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2014-05-02 14:27:47 +03:00
|
|
|
|
|
|
|
|
/* p1 and p2 divider */
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port),
|
|
|
|
|
5 << DPIO_CHV_S1_DIV_SHIFT |
|
|
|
|
|
bestp1 << DPIO_CHV_P1_DIV_SHIFT |
|
|
|
|
|
bestp2 << DPIO_CHV_P2_DIV_SHIFT |
|
|
|
|
|
1 << DPIO_CHV_K_DIV_SHIFT);
|
|
|
|
|
|
|
|
|
|
/* Feedback post-divider - m2 */
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2);
|
|
|
|
|
|
|
|
|
|
/* Feedback refclk divider - n and m1 */
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port),
|
|
|
|
|
DPIO_CHV_M1_DIV_BY_2 |
|
|
|
|
|
1 << DPIO_CHV_N_DIV_SHIFT);
|
|
|
|
|
|
|
|
|
|
/* M2 fraction division */
|
2015-07-08 23:45:47 +03:00
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac);
|
2014-05-02 14:27:47 +03:00
|
|
|
|
|
|
|
|
/* M2 fraction division enable */
|
2015-03-05 19:30:57 +05:30
|
|
|
dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
|
|
|
|
|
dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN);
|
|
|
|
|
dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT);
|
|
|
|
|
if (bestm2_frac)
|
|
|
|
|
dpio_val |= DPIO_CHV_FRAC_DIV_EN;
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val);
|
2014-05-02 14:27:47 +03:00
|
|
|
|
2015-03-05 19:32:06 +05:30
|
|
|
/* Program digital lock detect threshold */
|
|
|
|
|
dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port));
|
|
|
|
|
dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK |
|
|
|
|
|
DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE);
|
|
|
|
|
dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT);
|
|
|
|
|
if (!bestm2_frac)
|
|
|
|
|
dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE;
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val);
|
|
|
|
|
|
2014-05-02 14:27:47 +03:00
|
|
|
/* Loop filter */
|
2015-03-05 19:33:08 +05:30
|
|
|
if (vco == 5400000) {
|
|
|
|
|
loopfilter |= (0x3 << DPIO_CHV_PROP_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x8 << DPIO_CHV_INT_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x1 << DPIO_CHV_GAIN_CTRL_SHIFT);
|
|
|
|
|
tribuf_calcntr = 0x9;
|
|
|
|
|
} else if (vco <= 6200000) {
|
|
|
|
|
loopfilter |= (0x5 << DPIO_CHV_PROP_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0xB << DPIO_CHV_INT_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT);
|
|
|
|
|
tribuf_calcntr = 0x9;
|
|
|
|
|
} else if (vco <= 6480000) {
|
|
|
|
|
loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT);
|
|
|
|
|
tribuf_calcntr = 0x8;
|
|
|
|
|
} else {
|
|
|
|
|
/* Not supported. Apply the same limits as in the max case */
|
|
|
|
|
loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT);
|
|
|
|
|
loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT);
|
|
|
|
|
tribuf_calcntr = 0;
|
|
|
|
|
}
|
2014-05-02 14:27:47 +03:00
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter);
|
|
|
|
|
|
2015-03-11 22:52:08 +02:00
|
|
|
dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port));
|
2015-03-05 19:33:08 +05:30
|
|
|
dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK;
|
|
|
|
|
dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT);
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val);
|
|
|
|
|
|
2014-05-02 14:27:47 +03:00
|
|
|
/* AFC Recal */
|
|
|
|
|
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port),
|
|
|
|
|
vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) |
|
|
|
|
|
DPIO_AFC_RECAL);
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2014-05-02 14:27:47 +03:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 13:20:22 +02:00
|
|
|
/**
|
|
|
|
|
* vlv_force_pll_on - forcibly enable just the PLL
|
|
|
|
|
* @dev_priv: i915 private structure
|
|
|
|
|
* @pipe: pipe PLL to enable
|
|
|
|
|
* @dpll: PLL configuration
|
|
|
|
|
*
|
|
|
|
|
* Enable the PLL for @pipe using the supplied @dpll config. To be used
|
|
|
|
|
* in cases where we need the PLL enabled even when @pipe is not going to
|
|
|
|
|
* be enabled.
|
|
|
|
|
*/
|
2016-10-31 22:37:07 +02:00
|
|
|
int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe,
|
2016-01-19 15:25:17 +00:00
|
|
|
const struct dpll *dpll)
|
2014-10-28 13:20:22 +02:00
|
|
|
{
|
2016-10-31 22:37:09 +02:00
|
|
|
struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
2016-01-19 15:25:17 +00:00
|
|
|
struct intel_crtc_state *pipe_config;
|
|
|
|
|
|
|
|
|
|
pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
|
|
|
|
|
if (!pipe_config)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
pipe_config->base.crtc = &crtc->base;
|
|
|
|
|
pipe_config->pixel_multiplier = 1;
|
|
|
|
|
pipe_config->dpll = *dpll;
|
2014-10-28 13:20:22 +02:00
|
|
|
|
2016-10-31 22:37:07 +02:00
|
|
|
if (IS_CHERRYVIEW(dev_priv)) {
|
2016-01-19 15:25:17 +00:00
|
|
|
chv_compute_dpll(crtc, pipe_config);
|
|
|
|
|
chv_prepare_pll(crtc, pipe_config);
|
|
|
|
|
chv_enable_pll(crtc, pipe_config);
|
2014-10-28 13:20:22 +02:00
|
|
|
} else {
|
2016-01-19 15:25:17 +00:00
|
|
|
vlv_compute_dpll(crtc, pipe_config);
|
|
|
|
|
vlv_prepare_pll(crtc, pipe_config);
|
|
|
|
|
vlv_enable_pll(crtc, pipe_config);
|
2014-10-28 13:20:22 +02:00
|
|
|
}
|
2016-01-19 15:25:17 +00:00
|
|
|
|
|
|
|
|
kfree(pipe_config);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2014-10-28 13:20:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* vlv_force_pll_off - forcibly disable just the PLL
|
|
|
|
|
* @dev_priv: i915 private structure
|
|
|
|
|
* @pipe: pipe PLL to disable
|
|
|
|
|
*
|
|
|
|
|
* Disable the PLL for @pipe. To be used in cases where we need
|
|
|
|
|
* the PLL enabled even when @pipe is not going to be enabled.
|
|
|
|
|
*/
|
2016-10-31 22:37:07 +02:00
|
|
|
void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe)
|
2014-10-28 13:20:22 +02:00
|
|
|
{
|
2016-10-31 22:37:07 +02:00
|
|
|
if (IS_CHERRYVIEW(dev_priv))
|
|
|
|
|
chv_disable_pll(dev_priv, pipe);
|
2014-10-28 13:20:22 +02:00
|
|
|
else
|
2016-10-31 22:37:07 +02:00
|
|
|
vlv_disable_pll(dev_priv, pipe);
|
2014-10-28 13:20:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-18 10:30:24 +02:00
|
|
|
static void i9xx_compute_dpll(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll *reduced_clock)
|
2012-03-28 23:12:16 +02:00
|
|
|
{
|
2016-10-31 22:37:15 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2012-03-28 23:12:16 +02:00
|
|
|
u32 dpll;
|
2015-01-15 14:55:23 +02:00
|
|
|
struct dpll *clock = &crtc_state->dpll;
|
2012-03-28 23:12:16 +02:00
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
|
2012-09-27 19:13:06 +05:30
|
|
|
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll = DPLL_VGA_MODE_DIS;
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= DPLLB_MODE_LVDS;
|
|
|
|
|
else
|
|
|
|
|
dpll |= DPLLB_MODE_DAC_SERIAL;
|
2013-03-27 00:44:53 +01:00
|
|
|
|
2016-12-07 22:48:09 +02:00
|
|
|
if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
|
|
|
|
|
IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
|
2015-01-15 14:55:23 +02:00
|
|
|
dpll |= (crtc_state->pixel_multiplier - 1)
|
2013-04-19 11:14:37 +02:00
|
|
|
<< SDVO_MULTIPLIER_SHIFT_HIRES;
|
2012-03-28 23:12:16 +02:00
|
|
|
}
|
2013-04-19 11:14:37 +02:00
|
|
|
|
2016-06-22 21:57:03 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
|
|
|
|
|
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
2013-07-06 12:52:05 +02:00
|
|
|
dpll |= DPLL_SDVO_HIGH_SPEED;
|
2013-04-19 11:14:37 +02:00
|
|
|
|
2016-06-22 21:57:04 +03:00
|
|
|
if (intel_crtc_has_dp_encoder(crtc_state))
|
2013-07-06 12:52:05 +02:00
|
|
|
dpll |= DPLL_SDVO_HIGH_SPEED;
|
2012-03-28 23:12:16 +02:00
|
|
|
|
|
|
|
|
/* compute bitmask from p1 value */
|
2016-10-31 22:37:15 +02:00
|
|
|
if (IS_PINEVIEW(dev_priv))
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
|
|
|
|
|
else {
|
|
|
|
|
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv) && reduced_clock)
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
|
|
|
|
|
}
|
|
|
|
|
switch (clock->p2) {
|
|
|
|
|
case 5:
|
|
|
|
|
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
|
|
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
|
|
|
|
|
break;
|
|
|
|
|
case 14:
|
|
|
|
|
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-31 22:37:15 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
|
|
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
if (crtc_state->sdvo_tv_clock)
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= PLL_REF_INPUT_TVCLKINBC;
|
2016-06-22 21:57:02 +03:00
|
|
|
else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
|
2016-03-21 18:00:02 +02:00
|
|
|
intel_panel_use_ssc(dev_priv))
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
|
|
|
|
|
else
|
|
|
|
|
dpll |= PLL_REF_INPUT_DREFCLK;
|
|
|
|
|
|
|
|
|
|
dpll |= DPLL_VCO_ENABLE;
|
2015-01-15 14:55:23 +02:00
|
|
|
crtc_state->dpll_hw_state.dpll = dpll;
|
2013-06-05 13:34:28 +02:00
|
|
|
|
2016-10-31 22:37:15 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2015-01-15 14:55:23 +02:00
|
|
|
u32 dpll_md = (crtc_state->pixel_multiplier - 1)
|
2013-06-01 17:17:04 +02:00
|
|
|
<< DPLL_MD_UDI_MULTIPLIER_SHIFT;
|
2015-01-15 14:55:23 +02:00
|
|
|
crtc_state->dpll_hw_state.dpll_md = dpll_md;
|
2012-03-28 23:12:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-18 10:30:24 +02:00
|
|
|
static void i8xx_compute_dpll(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll *reduced_clock)
|
2012-03-28 23:12:16 +02:00
|
|
|
{
|
2013-03-28 10:42:02 +01:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2012-03-28 23:12:16 +02:00
|
|
|
u32 dpll;
|
2015-01-15 14:55:23 +02:00
|
|
|
struct dpll *clock = &crtc_state->dpll;
|
2012-03-28 23:12:16 +02:00
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
|
2012-09-27 19:13:06 +05:30
|
|
|
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll = DPLL_VGA_MODE_DIS;
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
|
|
|
|
|
} else {
|
|
|
|
|
if (clock->p1 == 2)
|
|
|
|
|
dpll |= PLL_P1_DIVIDE_BY_TWO;
|
|
|
|
|
else
|
|
|
|
|
dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
|
|
|
|
|
if (clock->p2 == 4)
|
|
|
|
|
dpll |= PLL_P2_DIVIDE_BY_4;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:02:58 +01:00
|
|
|
if (!IS_I830(dev_priv) &&
|
|
|
|
|
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO))
|
2013-07-06 12:52:05 +02:00
|
|
|
dpll |= DPLL_DVO_2X_MODE;
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
|
2016-03-21 18:00:02 +02:00
|
|
|
intel_panel_use_ssc(dev_priv))
|
2012-03-28 23:12:16 +02:00
|
|
|
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
|
|
|
|
|
else
|
|
|
|
|
dpll |= PLL_REF_INPUT_DREFCLK;
|
|
|
|
|
|
|
|
|
|
dpll |= DPLL_VCO_ENABLE;
|
2015-01-15 14:55:23 +02:00
|
|
|
crtc_state->dpll_hw_state.dpll = dpll;
|
2012-03-28 23:12:16 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-01 17:16:22 +02:00
|
|
|
static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
|
2012-10-01 18:10:53 -03:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
2012-10-01 18:10:53 -03:00
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
2015-01-15 14:55:25 +02:00
|
|
|
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
|
2015-09-08 13:40:49 +03:00
|
|
|
const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
|
2014-03-28 23:29:32 +02:00
|
|
|
uint32_t crtc_vtotal, crtc_vblank_end;
|
|
|
|
|
int vsyncshift = 0;
|
2013-05-03 11:49:51 +02:00
|
|
|
|
|
|
|
|
/* We need to be careful not to changed the adjusted mode, for otherwise
|
|
|
|
|
* the hw state checker will get angry at the mismatch. */
|
|
|
|
|
crtc_vtotal = adjusted_mode->crtc_vtotal;
|
|
|
|
|
crtc_vblank_end = adjusted_mode->crtc_vblank_end;
|
2012-10-01 18:10:53 -03:00
|
|
|
|
2014-03-28 23:29:30 +02:00
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
2012-10-01 18:10:53 -03:00
|
|
|
/* the chip adds 2 halflines automatically */
|
2013-05-03 11:49:51 +02:00
|
|
|
crtc_vtotal -= 1;
|
|
|
|
|
crtc_vblank_end -= 1;
|
2014-03-28 23:29:30 +02:00
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
|
2014-03-28 23:29:30 +02:00
|
|
|
vsyncshift = (adjusted_mode->crtc_htotal - 1) / 2;
|
|
|
|
|
else
|
|
|
|
|
vsyncshift = adjusted_mode->crtc_hsync_start -
|
|
|
|
|
adjusted_mode->crtc_htotal / 2;
|
2014-03-28 23:29:32 +02:00
|
|
|
if (vsyncshift < 0)
|
|
|
|
|
vsyncshift += adjusted_mode->crtc_htotal;
|
2012-10-01 18:10:53 -03:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) > 3)
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(VSYNCSHIFT(cpu_transcoder), vsyncshift);
|
2012-10-01 18:10:53 -03:00
|
|
|
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(HTOTAL(cpu_transcoder),
|
2012-10-01 18:10:53 -03:00
|
|
|
(adjusted_mode->crtc_hdisplay - 1) |
|
|
|
|
|
((adjusted_mode->crtc_htotal - 1) << 16));
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(HBLANK(cpu_transcoder),
|
2012-10-01 18:10:53 -03:00
|
|
|
(adjusted_mode->crtc_hblank_start - 1) |
|
|
|
|
|
((adjusted_mode->crtc_hblank_end - 1) << 16));
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(HSYNC(cpu_transcoder),
|
2012-10-01 18:10:53 -03:00
|
|
|
(adjusted_mode->crtc_hsync_start - 1) |
|
|
|
|
|
((adjusted_mode->crtc_hsync_end - 1) << 16));
|
|
|
|
|
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(VTOTAL(cpu_transcoder),
|
2012-10-01 18:10:53 -03:00
|
|
|
(adjusted_mode->crtc_vdisplay - 1) |
|
2013-05-03 11:49:51 +02:00
|
|
|
((crtc_vtotal - 1) << 16));
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(VBLANK(cpu_transcoder),
|
2012-10-01 18:10:53 -03:00
|
|
|
(adjusted_mode->crtc_vblank_start - 1) |
|
2013-05-03 11:49:51 +02:00
|
|
|
((crtc_vblank_end - 1) << 16));
|
2012-10-23 18:30:02 -02:00
|
|
|
I915_WRITE(VSYNC(cpu_transcoder),
|
2012-10-01 18:10:53 -03:00
|
|
|
(adjusted_mode->crtc_vsync_start - 1) |
|
|
|
|
|
((adjusted_mode->crtc_vsync_end - 1) << 16));
|
|
|
|
|
|
2012-10-24 11:34:43 -02:00
|
|
|
/* Workaround: when the EDP input selection is B, the VTOTAL_B must be
|
|
|
|
|
* programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is
|
|
|
|
|
* documented on the DDI_FUNC_CTL register description, EDP Input Select
|
|
|
|
|
* bits. */
|
2016-10-13 11:03:01 +01:00
|
|
|
if (IS_HASWELL(dev_priv) && cpu_transcoder == TRANSCODER_EDP &&
|
2012-10-24 11:34:43 -02:00
|
|
|
(pipe == PIPE_B || pipe == PIPE_C))
|
|
|
|
|
I915_WRITE(VTOTAL(pipe), I915_READ(VTOTAL(cpu_transcoder)));
|
|
|
|
|
|
2016-03-18 17:05:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_set_pipe_src_size(struct intel_crtc *intel_crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = intel_crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-18 17:05:39 +02:00
|
|
|
enum pipe pipe = intel_crtc->pipe;
|
|
|
|
|
|
2012-10-01 18:10:53 -03:00
|
|
|
/* pipesrc controls the size that is scaled from, which should
|
|
|
|
|
* always be the user's requested size.
|
|
|
|
|
*/
|
|
|
|
|
I915_WRITE(PIPESRC(pipe),
|
2015-01-15 14:55:25 +02:00
|
|
|
((intel_crtc->config->pipe_src_w - 1) << 16) |
|
|
|
|
|
(intel_crtc->config->pipe_src_h - 1));
|
2012-10-01 18:10:53 -03:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 21:56:12 +02:00
|
|
|
static void intel_get_pipe_timings(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-04-29 21:56:12 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-04-29 21:56:12 +02:00
|
|
|
enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
|
|
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
|
|
tmp = I915_READ(HTOTAL(cpu_transcoder));
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
tmp = I915_READ(HBLANK(cpu_transcoder));
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
tmp = I915_READ(HSYNC(cpu_transcoder));
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
|
|
|
|
|
tmp = I915_READ(VTOTAL(cpu_transcoder));
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
tmp = I915_READ(VBLANK(cpu_transcoder));
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
tmp = I915_READ(VSYNC(cpu_transcoder));
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
|
|
|
|
|
if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) {
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_vtotal += 1;
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_vblank_end += 1;
|
2013-04-29 21:56:12 +02:00
|
|
|
}
|
2016-03-18 17:05:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_get_pipe_src_size(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-18 17:05:39 +02:00
|
|
|
u32 tmp;
|
2013-04-29 21:56:12 +02:00
|
|
|
|
|
|
|
|
tmp = I915_READ(PIPESRC(crtc->pipe));
|
2013-09-04 18:25:28 +03:00
|
|
|
pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
|
|
|
|
|
pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1;
|
|
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.mode.vdisplay = pipe_config->pipe_src_h;
|
|
|
|
|
pipe_config->base.mode.hdisplay = pipe_config->pipe_src_w;
|
2013-04-29 21:56:12 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-11 15:28:57 -08:00
|
|
|
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-06-26 18:57:38 +03:00
|
|
|
{
|
2015-01-15 14:55:22 +02:00
|
|
|
mode->hdisplay = pipe_config->base.adjusted_mode.crtc_hdisplay;
|
|
|
|
|
mode->htotal = pipe_config->base.adjusted_mode.crtc_htotal;
|
|
|
|
|
mode->hsync_start = pipe_config->base.adjusted_mode.crtc_hsync_start;
|
|
|
|
|
mode->hsync_end = pipe_config->base.adjusted_mode.crtc_hsync_end;
|
2013-06-26 18:57:38 +03:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
mode->vdisplay = pipe_config->base.adjusted_mode.crtc_vdisplay;
|
|
|
|
|
mode->vtotal = pipe_config->base.adjusted_mode.crtc_vtotal;
|
|
|
|
|
mode->vsync_start = pipe_config->base.adjusted_mode.crtc_vsync_start;
|
|
|
|
|
mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end;
|
2013-06-26 18:57:38 +03:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
mode->flags = pipe_config->base.adjusted_mode.flags;
|
2015-07-14 14:12:02 +02:00
|
|
|
mode->type = DRM_MODE_TYPE_DRIVER;
|
2013-06-26 18:57:38 +03:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
mode->clock = pipe_config->base.adjusted_mode.crtc_clock;
|
2015-07-14 14:12:02 +02:00
|
|
|
|
|
|
|
|
mode->hsync = drm_mode_hsync(mode);
|
|
|
|
|
mode->vrefresh = drm_mode_vrefresh(mode);
|
|
|
|
|
drm_mode_set_name(mode);
|
2013-06-26 18:57:38 +03:00
|
|
|
}
|
|
|
|
|
|
2013-02-19 18:48:54 +01:00
|
|
|
static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
|
|
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
2013-02-19 18:48:54 +01:00
|
|
|
uint32_t pipeconf;
|
|
|
|
|
|
2013-06-13 00:54:58 +02:00
|
|
|
pipeconf = 0;
|
2013-02-19 18:48:54 +01:00
|
|
|
|
2017-06-01 17:36:19 +03:00
|
|
|
/* we keep both pipes enabled on 830 */
|
|
|
|
|
if (IS_I830(dev_priv))
|
2014-08-15 01:22:07 +03:00
|
|
|
pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
|
2013-09-24 11:46:14 +02:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->double_wide)
|
2013-09-04 18:30:02 +03:00
|
|
|
pipeconf |= PIPECONF_DOUBLE_WIDE;
|
2013-02-19 18:48:54 +01:00
|
|
|
|
2013-04-24 14:57:17 +02:00
|
|
|
/* only g4x and later have fancy bpc/dither controls */
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
|
|
|
|
|
IS_CHERRYVIEW(dev_priv)) {
|
2013-04-24 14:57:17 +02:00
|
|
|
/* Bspec claims that we can't use dithering for 30bpp pipes. */
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->dither && intel_crtc->config->pipe_bpp != 30)
|
2013-04-24 14:57:17 +02:00
|
|
|
pipeconf |= PIPECONF_DITHER_EN |
|
2013-02-19 18:48:54 +01:00
|
|
|
PIPECONF_DITHER_TYPE_SP;
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
switch (intel_crtc->config->pipe_bpp) {
|
2013-04-24 14:57:17 +02:00
|
|
|
case 18:
|
|
|
|
|
pipeconf |= PIPECONF_6BPC;
|
|
|
|
|
break;
|
|
|
|
|
case 24:
|
|
|
|
|
pipeconf |= PIPECONF_8BPC;
|
|
|
|
|
break;
|
|
|
|
|
case 30:
|
|
|
|
|
pipeconf |= PIPECONF_10BPC;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Case prevented by intel_choose_pipe_bpp_dither. */
|
|
|
|
|
BUG();
|
2013-02-19 18:48:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 4 ||
|
2016-06-22 21:57:02 +03:00
|
|
|
intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_SDVO))
|
2014-03-28 23:29:31 +02:00
|
|
|
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
|
|
|
|
|
else
|
|
|
|
|
pipeconf |= PIPECONF_INTERLACE_W_SYNC_SHIFT;
|
|
|
|
|
} else
|
2013-02-19 18:48:54 +01:00
|
|
|
pipeconf |= PIPECONF_PROGRESSIVE;
|
|
|
|
|
|
2016-10-14 10:13:44 +01:00
|
|
|
if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
|
2015-12-09 12:29:35 -08:00
|
|
|
intel_crtc->config->limited_color_range)
|
2013-06-13 00:54:58 +02:00
|
|
|
pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
|
2013-04-02 16:10:09 +03:00
|
|
|
|
2013-02-19 18:48:54 +01:00
|
|
|
I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
|
|
|
|
|
POSTING_READ(PIPECONF(intel_crtc->pipe));
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-22 15:35:23 +02:00
|
|
|
static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit;
|
2016-03-22 15:35:23 +02:00
|
|
|
int refclk = 48000;
|
|
|
|
|
|
|
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2016-03-22 15:35:23 +02:00
|
|
|
if (intel_panel_use_ssc(dev_priv)) {
|
|
|
|
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
|
|
|
|
DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
limit = &intel_limits_i8xx_lvds;
|
2016-06-22 21:57:02 +03:00
|
|
|
} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO)) {
|
2016-03-22 15:35:23 +02:00
|
|
|
limit = &intel_limits_i8xx_dvo;
|
|
|
|
|
} else {
|
|
|
|
|
limit = &intel_limits_i8xx_dac;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->clock_set &&
|
|
|
|
|
!i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
|
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i8xx_compute_dpll(crtc, crtc_state, NULL);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:15 +02:00
|
|
|
static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit;
|
2016-03-21 18:00:15 +02:00
|
|
|
int refclk = 96000;
|
|
|
|
|
|
|
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2016-03-21 18:00:15 +02:00
|
|
|
if (intel_panel_use_ssc(dev_priv)) {
|
|
|
|
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
|
|
|
|
DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (intel_is_dual_link_lvds(dev))
|
|
|
|
|
limit = &intel_limits_g4x_dual_channel_lvds;
|
|
|
|
|
else
|
|
|
|
|
limit = &intel_limits_g4x_single_channel_lvds;
|
2016-06-22 21:57:02 +03:00
|
|
|
} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
|
|
|
|
|
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
|
2016-03-21 18:00:15 +02:00
|
|
|
limit = &intel_limits_g4x_hdmi;
|
2016-06-22 21:57:02 +03:00
|
|
|
} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) {
|
2016-03-21 18:00:15 +02:00
|
|
|
limit = &intel_limits_g4x_sdvo;
|
|
|
|
|
} else {
|
|
|
|
|
/* The option is for other outputs */
|
|
|
|
|
limit = &intel_limits_i9xx_sdvo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->clock_set &&
|
|
|
|
|
!g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
|
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i9xx_compute_dpll(crtc, crtc_state, NULL);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:16 +02:00
|
|
|
static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit;
|
2016-03-21 18:00:16 +02:00
|
|
|
int refclk = 96000;
|
|
|
|
|
|
|
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2016-03-21 18:00:16 +02:00
|
|
|
if (intel_panel_use_ssc(dev_priv)) {
|
|
|
|
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
|
|
|
|
DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
limit = &intel_limits_pineview_lvds;
|
|
|
|
|
} else {
|
|
|
|
|
limit = &intel_limits_pineview_sdvo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->clock_set &&
|
|
|
|
|
!pnv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
|
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i9xx_compute_dpll(crtc, crtc_state, NULL);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2014-10-20 13:46:44 +03:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit;
|
2016-03-22 15:35:23 +02:00
|
|
|
int refclk = 96000;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2015-05-15 13:34:29 +03:00
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2016-03-21 18:00:16 +02:00
|
|
|
if (intel_panel_use_ssc(dev_priv)) {
|
|
|
|
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
|
|
|
|
DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
|
|
|
|
|
}
|
2009-02-13 20:56:52 -05:00
|
|
|
|
2016-03-21 18:00:16 +02:00
|
|
|
limit = &intel_limits_i9xx_lvds;
|
|
|
|
|
} else {
|
|
|
|
|
limit = &intel_limits_i9xx_sdvo;
|
2016-03-22 15:35:23 +02:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-03-21 18:00:16 +02:00
|
|
|
if (!crtc_state->clock_set &&
|
|
|
|
|
!i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
|
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
2013-03-28 10:42:02 +01:00
|
|
|
}
|
2009-03-24 14:02:43 +08:00
|
|
|
|
2016-03-22 15:35:23 +02:00
|
|
|
i9xx_compute_dpll(crtc, crtc_state, NULL);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2014-04-24 23:55:04 +02:00
|
|
|
return 0;
|
2011-03-30 13:01:02 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:13 +02:00
|
|
|
static int chv_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
|
|
|
|
int refclk = 100000;
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit = &intel_limits_chv;
|
2016-03-21 18:00:13 +02:00
|
|
|
|
|
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->clock_set &&
|
|
|
|
|
!chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
|
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chv_compute_dpll(crtc, crtc_state);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
|
|
|
|
int refclk = 100000;
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit = &intel_limits_vlv;
|
2016-03-21 18:00:13 +02:00
|
|
|
|
|
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->clock_set &&
|
|
|
|
|
!vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
|
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vlv_compute_dpll(crtc, crtc_state);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-07 23:34:16 +02:00
|
|
|
static void i9xx_get_pfit_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-05-07 23:34:16 +02:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2013-05-07 23:34:16 +02:00
|
|
|
uint32_t tmp;
|
|
|
|
|
|
2016-10-13 11:02:58 +01:00
|
|
|
if (INTEL_GEN(dev_priv) <= 3 &&
|
|
|
|
|
(IS_I830(dev_priv) || !IS_MOBILE(dev_priv)))
|
2014-01-10 14:06:45 +02:00
|
|
|
return;
|
|
|
|
|
|
2013-05-07 23:34:16 +02:00
|
|
|
tmp = I915_READ(PFIT_CONTROL);
|
2013-07-11 13:35:40 +02:00
|
|
|
if (!(tmp & PFIT_ENABLE))
|
|
|
|
|
return;
|
2013-05-07 23:34:16 +02:00
|
|
|
|
2013-07-11 13:35:40 +02:00
|
|
|
/* Check whether the pfit is attached to our pipe. */
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 4) {
|
2013-05-07 23:34:16 +02:00
|
|
|
if (crtc->pipe != PIPE_B)
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-11 13:35:40 +02:00
|
|
|
pipe_config->gmch_pfit.control = tmp;
|
2013-05-07 23:34:16 +02:00
|
|
|
pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-20 11:29:32 -07:00
|
|
|
static void vlv_crtc_clock_get(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-09-20 11:29:32 -07:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-09-20 11:29:32 -07:00
|
|
|
int pipe = pipe_config->cpu_transcoder;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2013-09-20 11:29:32 -07:00
|
|
|
u32 mdiv;
|
2013-09-25 14:24:01 -07:00
|
|
|
int refclk = 100000;
|
2013-09-20 11:29:32 -07:00
|
|
|
|
2016-03-15 16:40:01 +02:00
|
|
|
/* In case of DSI, DPLL will not be used */
|
|
|
|
|
if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
|
2014-07-30 20:32:37 +05:30
|
|
|
return;
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2013-11-07 10:43:30 +08:00
|
|
|
mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2013-09-20 11:29:32 -07:00
|
|
|
|
|
|
|
|
clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7;
|
|
|
|
|
clock.m2 = mdiv & DPIO_M2DIV_MASK;
|
|
|
|
|
clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf;
|
|
|
|
|
clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7;
|
|
|
|
|
clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f;
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock);
|
2013-09-20 11:29:32 -07:00
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:52 +00:00
|
|
|
static void
|
|
|
|
|
i9xx_get_initial_plane_config(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_initial_plane_config *plane_config)
|
2014-03-07 08:57:49 -08:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-11-17 21:19:12 +02:00
|
|
|
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
|
|
|
|
|
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
|
|
|
|
|
enum pipe pipe = crtc->pipe;
|
2014-03-07 08:57:49 -08:00
|
|
|
u32 val, base, offset;
|
|
|
|
|
int fourcc, pixel_format;
|
2015-03-23 11:10:32 +00:00
|
|
|
unsigned int aligned_height;
|
2015-01-20 12:51:46 +00:00
|
|
|
struct drm_framebuffer *fb;
|
2015-01-21 13:50:54 +00:00
|
|
|
struct intel_framebuffer *intel_fb;
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2017-11-17 21:19:16 +02:00
|
|
|
if (!plane->get_hw_state(plane))
|
2015-02-05 19:35:13 +00:00
|
|
|
return;
|
|
|
|
|
|
2015-01-21 14:07:19 +00:00
|
|
|
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
|
2015-01-21 13:50:54 +00:00
|
|
|
if (!intel_fb) {
|
2014-03-07 08:57:49 -08:00
|
|
|
DRM_DEBUG_KMS("failed to alloc fb\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 13:50:54 +00:00
|
|
|
fb = &intel_fb->base;
|
|
|
|
|
|
2016-11-18 21:52:53 +02:00
|
|
|
fb->dev = dev;
|
|
|
|
|
|
2017-11-17 21:19:16 +02:00
|
|
|
val = I915_READ(DSPCNTR(i9xx_plane));
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2015-02-10 17:16:09 +00:00
|
|
|
if (val & DISPPLANE_TILED) {
|
2015-01-20 12:51:44 +00:00
|
|
|
plane_config->tiling = I915_TILING_X;
|
2016-11-16 13:33:16 +02:00
|
|
|
fb->modifier = I915_FORMAT_MOD_X_TILED;
|
2015-02-10 17:16:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-03-07 08:57:49 -08:00
|
|
|
|
|
|
|
|
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
|
2015-01-20 12:51:50 +00:00
|
|
|
fourcc = i9xx_format_to_fourcc(pixel_format);
|
2016-11-18 21:52:57 +02:00
|
|
|
fb->format = drm_format_info(fourcc);
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2017-11-17 21:19:13 +02:00
|
|
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
|
|
|
|
|
offset = I915_READ(DSPOFFSET(i9xx_plane));
|
|
|
|
|
base = I915_READ(DSPSURF(i9xx_plane)) & 0xfffff000;
|
|
|
|
|
} else if (INTEL_GEN(dev_priv) >= 4) {
|
2015-01-20 12:51:44 +00:00
|
|
|
if (plane_config->tiling)
|
2017-11-17 21:19:12 +02:00
|
|
|
offset = I915_READ(DSPTILEOFF(i9xx_plane));
|
2014-03-07 08:57:49 -08:00
|
|
|
else
|
2017-11-17 21:19:12 +02:00
|
|
|
offset = I915_READ(DSPLINOFF(i9xx_plane));
|
|
|
|
|
base = I915_READ(DSPSURF(i9xx_plane)) & 0xfffff000;
|
2014-03-07 08:57:49 -08:00
|
|
|
} else {
|
2017-11-17 21:19:12 +02:00
|
|
|
base = I915_READ(DSPADDR(i9xx_plane));
|
2014-03-07 08:57:49 -08:00
|
|
|
}
|
|
|
|
|
plane_config->base = base;
|
|
|
|
|
|
|
|
|
|
val = I915_READ(PIPESRC(pipe));
|
2015-01-20 12:51:46 +00:00
|
|
|
fb->width = ((val >> 16) & 0xfff) + 1;
|
|
|
|
|
fb->height = ((val >> 0) & 0xfff) + 1;
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
val = I915_READ(DSPSTRIDE(i9xx_plane));
|
2015-01-20 12:51:46 +00:00
|
|
|
fb->pitches[0] = val & 0xffffffc0;
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
aligned_height = intel_fb_align_height(fb, 0, fb->height);
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2015-02-10 23:12:27 +01:00
|
|
|
plane_config->size = fb->pitches[0] * aligned_height;
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
DRM_DEBUG_KMS("%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
|
|
|
|
|
crtc->base.name, plane->base.name, fb->width, fb->height,
|
2016-12-14 23:32:20 +02:00
|
|
|
fb->format->cpp[0] * 8, base, fb->pitches[0],
|
2015-01-20 12:51:48 +00:00
|
|
|
plane_config->size);
|
2014-03-07 08:57:49 -08:00
|
|
|
|
2015-02-05 17:22:18 +00:00
|
|
|
plane_config->fb = intel_fb;
|
2014-03-07 08:57:49 -08:00
|
|
|
}
|
|
|
|
|
|
2014-04-09 13:28:22 +03:00
|
|
|
static void chv_crtc_clock_get(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-04-09 13:28:22 +03:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-04-09 13:28:22 +03:00
|
|
|
int pipe = pipe_config->cpu_transcoder;
|
|
|
|
|
enum dpio_channel port = vlv_pipe_to_channel(pipe);
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2015-07-02 14:29:58 +03:00
|
|
|
u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3;
|
2014-04-09 13:28:22 +03:00
|
|
|
int refclk = 100000;
|
|
|
|
|
|
2016-03-15 16:40:01 +02:00
|
|
|
/* In case of DSI, DPLL will not be used */
|
|
|
|
|
if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2014-04-09 13:28:22 +03:00
|
|
|
cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port));
|
|
|
|
|
pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port));
|
|
|
|
|
pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port));
|
|
|
|
|
pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port));
|
2015-07-02 14:29:58 +03:00
|
|
|
pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2014-04-09 13:28:22 +03:00
|
|
|
|
|
|
|
|
clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0;
|
2015-07-02 14:29:58 +03:00
|
|
|
clock.m2 = (pll_dw0 & 0xff) << 22;
|
|
|
|
|
if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN)
|
|
|
|
|
clock.m2 |= pll_dw2 & 0x3fffff;
|
2014-04-09 13:28:22 +03:00
|
|
|
clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf;
|
|
|
|
|
clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7;
|
|
|
|
|
clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f;
|
|
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock);
|
2014-04-09 13:28:22 +03:00
|
|
|
}
|
|
|
|
|
|
2013-03-28 10:42:00 +01:00
|
|
|
static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-03-28 10:42:00 +01:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2016-02-12 18:55:11 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
2013-03-28 10:42:00 +01:00
|
|
|
uint32_t tmp;
|
2016-02-12 18:55:11 +02:00
|
|
|
bool ret;
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
2014-03-05 16:20:55 +02:00
|
|
|
return false;
|
|
|
|
|
|
2013-07-04 12:01:15 +02:00
|
|
|
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
|
2016-03-08 17:46:18 +02:00
|
|
|
pipe_config->shared_dpll = NULL;
|
2013-05-22 00:50:22 +02:00
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
ret = false;
|
|
|
|
|
|
2013-03-28 10:42:00 +01:00
|
|
|
tmp = I915_READ(PIPECONF(crtc->pipe));
|
|
|
|
|
if (!(tmp & PIPECONF_ENABLE))
|
2016-02-12 18:55:11 +02:00
|
|
|
goto out;
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
|
|
|
|
|
IS_CHERRYVIEW(dev_priv)) {
|
2013-09-06 23:29:00 +03:00
|
|
|
switch (tmp & PIPECONF_BPC_MASK) {
|
|
|
|
|
case PIPECONF_6BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 18;
|
|
|
|
|
break;
|
|
|
|
|
case PIPECONF_8BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 24;
|
|
|
|
|
break;
|
|
|
|
|
case PIPECONF_10BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 30;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 10:13:44 +01:00
|
|
|
if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
|
2015-12-09 12:29:35 -08:00
|
|
|
(tmp & PIPECONF_COLOR_RANGE_SELECT))
|
2014-04-24 23:54:49 +02:00
|
|
|
pipe_config->limited_color_range = true;
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 4)
|
2013-09-04 18:30:03 +03:00
|
|
|
pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
|
|
|
|
|
|
2013-04-29 21:56:12 +02:00
|
|
|
intel_get_pipe_timings(crtc, pipe_config);
|
2016-03-18 17:05:39 +02:00
|
|
|
intel_get_pipe_src_size(crtc, pipe_config);
|
2013-04-29 21:56:12 +02:00
|
|
|
|
2013-05-07 23:34:16 +02:00
|
|
|
i9xx_get_pfit_config(crtc, pipe_config);
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2016-03-15 16:39:56 +02:00
|
|
|
/* No way to read it out on pipes B and C */
|
2016-10-14 10:13:44 +01:00
|
|
|
if (IS_CHERRYVIEW(dev_priv) && crtc->pipe != PIPE_A)
|
2016-03-15 16:39:56 +02:00
|
|
|
tmp = dev_priv->chv_dpll_md[crtc->pipe];
|
|
|
|
|
else
|
|
|
|
|
tmp = I915_READ(DPLL_MD(crtc->pipe));
|
2013-06-06 12:45:25 +02:00
|
|
|
pipe_config->pixel_multiplier =
|
|
|
|
|
((tmp & DPLL_MD_UDI_MULTIPLIER_MASK)
|
|
|
|
|
>> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1;
|
2013-06-05 13:34:28 +02:00
|
|
|
pipe_config->dpll_hw_state.dpll_md = tmp;
|
2016-10-13 11:02:58 +01:00
|
|
|
} else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
|
2016-12-07 22:48:09 +02:00
|
|
|
IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
|
2013-06-06 12:45:25 +02:00
|
|
|
tmp = I915_READ(DPLL(crtc->pipe));
|
|
|
|
|
pipe_config->pixel_multiplier =
|
|
|
|
|
((tmp & SDVO_MULTIPLIER_MASK)
|
|
|
|
|
>> SDVO_MULTIPLIER_SHIFT_HIRES) + 1;
|
|
|
|
|
} else {
|
|
|
|
|
/* Note that on i915G/GM the pixel multiplier is in the sdvo
|
|
|
|
|
* port and will be fixed up in the encoder->get_config
|
|
|
|
|
* function. */
|
|
|
|
|
pipe_config->pixel_multiplier = 1;
|
|
|
|
|
}
|
2013-06-05 13:34:28 +02:00
|
|
|
pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe));
|
2016-10-14 10:13:44 +01:00
|
|
|
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) {
|
2014-09-05 21:52:42 +03:00
|
|
|
/*
|
|
|
|
|
* DPLL_DVO_2X_MODE must be enabled for both DPLLs
|
|
|
|
|
* on 830. Filter it out here so that we don't
|
|
|
|
|
* report errors due to that.
|
|
|
|
|
*/
|
2016-10-13 11:02:58 +01:00
|
|
|
if (IS_I830(dev_priv))
|
2014-09-05 21:52:42 +03:00
|
|
|
pipe_config->dpll_hw_state.dpll &= ~DPLL_DVO_2X_MODE;
|
|
|
|
|
|
2013-06-05 13:34:28 +02:00
|
|
|
pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe));
|
|
|
|
|
pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe));
|
2013-06-26 17:44:15 +03:00
|
|
|
} else {
|
|
|
|
|
/* Mask out read-only status bits. */
|
|
|
|
|
pipe_config->dpll_hw_state.dpll &= ~(DPLL_LOCK_VLV |
|
|
|
|
|
DPLL_PORTC_READY_MASK |
|
|
|
|
|
DPLL_PORTB_READY_MASK);
|
2013-06-05 13:34:28 +02:00
|
|
|
}
|
2013-06-06 12:45:25 +02:00
|
|
|
|
2016-10-14 10:13:44 +01:00
|
|
|
if (IS_CHERRYVIEW(dev_priv))
|
2014-04-09 13:28:22 +03:00
|
|
|
chv_crtc_clock_get(crtc, pipe_config);
|
2016-10-13 11:03:08 +01:00
|
|
|
else if (IS_VALLEYVIEW(dev_priv))
|
2013-09-20 11:29:32 -07:00
|
|
|
vlv_crtc_clock_get(crtc, pipe_config);
|
|
|
|
|
else
|
|
|
|
|
i9xx_crtc_clock_get(crtc, pipe_config);
|
2013-09-13 16:00:08 +03:00
|
|
|
|
2015-08-26 19:39:18 +03:00
|
|
|
/*
|
|
|
|
|
* Normally the dotclock is filled in by the encoder .get_config()
|
|
|
|
|
* but in case the pipe is enabled w/o any ports we need a sane
|
|
|
|
|
* default.
|
|
|
|
|
*/
|
|
|
|
|
pipe_config->base.adjusted_mode.crtc_clock =
|
|
|
|
|
pipe_config->port_clock / pipe_config->pixel_multiplier;
|
|
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
ret = true;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
|
|
|
|
|
return ret;
|
2013-03-28 10:42:00 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
static void ironlake_init_pch_refclk(struct drm_i915_private *dev_priv)
|
2011-08-03 12:59:20 -07:00
|
|
|
{
|
|
|
|
|
struct intel_encoder *encoder;
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
int i;
|
2013-03-26 16:33:04 -07:00
|
|
|
u32 val, final;
|
2011-08-03 12:59:20 -07:00
|
|
|
bool has_lvds = false;
|
2011-09-22 12:01:57 -07:00
|
|
|
bool has_cpu_edp = false;
|
|
|
|
|
bool has_panel = false;
|
2011-09-26 14:29:12 -07:00
|
|
|
bool has_ck505 = false;
|
|
|
|
|
bool can_ssc = false;
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
bool using_ssc_source = false;
|
2011-08-03 12:59:20 -07:00
|
|
|
|
|
|
|
|
/* We need to take the global config into account */
|
2016-11-23 16:21:44 +02:00
|
|
|
for_each_intel_encoder(&dev_priv->drm, encoder) {
|
2011-09-22 12:01:57 -07:00
|
|
|
switch (encoder->type) {
|
|
|
|
|
case INTEL_OUTPUT_LVDS:
|
|
|
|
|
has_panel = true;
|
|
|
|
|
has_lvds = true;
|
|
|
|
|
break;
|
|
|
|
|
case INTEL_OUTPUT_EDP:
|
|
|
|
|
has_panel = true;
|
2017-11-09 17:24:34 +02:00
|
|
|
if (encoder->port == PORT_A)
|
2011-09-22 12:01:57 -07:00
|
|
|
has_cpu_edp = true;
|
|
|
|
|
break;
|
2014-10-27 17:47:52 -02:00
|
|
|
default:
|
|
|
|
|
break;
|
2011-08-03 12:59:20 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_IBX(dev_priv)) {
|
2013-05-09 20:03:18 -03:00
|
|
|
has_ck505 = dev_priv->vbt.display_clock_mode;
|
2011-09-26 14:29:12 -07:00
|
|
|
can_ssc = has_ck505;
|
|
|
|
|
} else {
|
|
|
|
|
has_ck505 = false;
|
|
|
|
|
can_ssc = true;
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
/* Check if any DPLLs are using the SSC source */
|
|
|
|
|
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
|
|
|
|
|
u32 temp = I915_READ(PCH_DPLL(i));
|
|
|
|
|
|
|
|
|
|
if (!(temp & DPLL_VCO_ENABLE))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if ((temp & PLL_REF_INPUT_MASK) ==
|
|
|
|
|
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
|
|
|
|
|
using_ssc_source = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n",
|
|
|
|
|
has_panel, has_lvds, has_ck505, using_ssc_source);
|
2011-08-03 12:59:20 -07:00
|
|
|
|
|
|
|
|
/* Ironlake: try to setup display ref clock before DPLL
|
|
|
|
|
* enabling. This is only under driver's control after
|
|
|
|
|
* PCH B stepping, previous chipset stepping should be
|
|
|
|
|
* ignoring this setting.
|
|
|
|
|
*/
|
2013-03-26 16:33:04 -07:00
|
|
|
val = I915_READ(PCH_DREF_CONTROL);
|
|
|
|
|
|
|
|
|
|
/* As we must carefully and slowly disable/enable each source in turn,
|
|
|
|
|
* compute the final state we want first and check if we need to
|
|
|
|
|
* make any changes at all.
|
|
|
|
|
*/
|
|
|
|
|
final = val;
|
|
|
|
|
final &= ~DREF_NONSPREAD_SOURCE_MASK;
|
|
|
|
|
if (has_ck505)
|
|
|
|
|
final |= DREF_NONSPREAD_CK505_ENABLE;
|
|
|
|
|
else
|
|
|
|
|
final |= DREF_NONSPREAD_SOURCE_ENABLE;
|
|
|
|
|
|
2016-06-09 18:39:07 +02:00
|
|
|
final &= ~DREF_SSC_SOURCE_MASK;
|
2013-03-26 16:33:04 -07:00
|
|
|
final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
2016-06-09 18:39:07 +02:00
|
|
|
final &= ~DREF_SSC1_ENABLE;
|
2013-03-26 16:33:04 -07:00
|
|
|
|
|
|
|
|
if (has_panel) {
|
|
|
|
|
final |= DREF_SSC_SOURCE_ENABLE;
|
|
|
|
|
|
|
|
|
|
if (intel_panel_use_ssc(dev_priv) && can_ssc)
|
|
|
|
|
final |= DREF_SSC1_ENABLE;
|
|
|
|
|
|
|
|
|
|
if (has_cpu_edp) {
|
|
|
|
|
if (intel_panel_use_ssc(dev_priv) && can_ssc)
|
|
|
|
|
final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
|
|
|
|
|
else
|
|
|
|
|
final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
|
|
|
|
|
} else
|
|
|
|
|
final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
} else if (using_ssc_source) {
|
|
|
|
|
final |= DREF_SSC_SOURCE_ENABLE;
|
|
|
|
|
final |= DREF_SSC1_ENABLE;
|
2013-03-26 16:33:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (final == val)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-08-03 12:59:20 -07:00
|
|
|
/* Always enable nonspread source */
|
2013-03-26 16:33:04 -07:00
|
|
|
val &= ~DREF_NONSPREAD_SOURCE_MASK;
|
2011-08-03 12:59:20 -07:00
|
|
|
|
2011-09-26 14:29:12 -07:00
|
|
|
if (has_ck505)
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_NONSPREAD_CK505_ENABLE;
|
2011-09-26 14:29:12 -07:00
|
|
|
else
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_NONSPREAD_SOURCE_ENABLE;
|
2011-08-03 12:59:20 -07:00
|
|
|
|
2011-09-22 12:01:57 -07:00
|
|
|
if (has_panel) {
|
2013-03-26 16:33:04 -07:00
|
|
|
val &= ~DREF_SSC_SOURCE_MASK;
|
|
|
|
|
val |= DREF_SSC_SOURCE_ENABLE;
|
2011-08-03 12:59:20 -07:00
|
|
|
|
2011-09-22 12:01:57 -07:00
|
|
|
/* SSC must be turned on before enabling the CPU output */
|
2011-09-26 14:29:12 -07:00
|
|
|
if (intel_panel_use_ssc(dev_priv) && can_ssc) {
|
2011-09-22 12:01:57 -07:00
|
|
|
DRM_DEBUG_KMS("Using SSC on panel\n");
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_SSC1_ENABLE;
|
2012-03-30 22:14:05 +02:00
|
|
|
} else
|
2013-03-26 16:33:04 -07:00
|
|
|
val &= ~DREF_SSC1_ENABLE;
|
2011-09-22 12:01:57 -07:00
|
|
|
|
|
|
|
|
/* Get SSC going before enabling the outputs */
|
2013-03-26 16:33:04 -07:00
|
|
|
I915_WRITE(PCH_DREF_CONTROL, val);
|
2011-09-22 12:01:57 -07:00
|
|
|
POSTING_READ(PCH_DREF_CONTROL);
|
|
|
|
|
udelay(200);
|
|
|
|
|
|
2013-03-26 16:33:04 -07:00
|
|
|
val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
2011-08-03 12:59:20 -07:00
|
|
|
|
|
|
|
|
/* Enable CPU source on CPU attached eDP */
|
2011-09-22 12:01:57 -07:00
|
|
|
if (has_cpu_edp) {
|
2011-09-26 14:29:12 -07:00
|
|
|
if (intel_panel_use_ssc(dev_priv) && can_ssc) {
|
2011-09-22 12:01:57 -07:00
|
|
|
DRM_DEBUG_KMS("Using SSC on eDP\n");
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
|
2014-05-18 02:24:50 +02:00
|
|
|
} else
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
|
2011-09-22 12:01:57 -07:00
|
|
|
} else
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
|
2011-09-22 12:01:57 -07:00
|
|
|
|
2013-03-26 16:33:04 -07:00
|
|
|
I915_WRITE(PCH_DREF_CONTROL, val);
|
2011-09-22 12:01:57 -07:00
|
|
|
POSTING_READ(PCH_DREF_CONTROL);
|
|
|
|
|
udelay(200);
|
|
|
|
|
} else {
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
DRM_DEBUG_KMS("Disabling CPU source output\n");
|
2011-09-22 12:01:57 -07:00
|
|
|
|
2013-03-26 16:33:04 -07:00
|
|
|
val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
2011-09-22 12:01:57 -07:00
|
|
|
|
|
|
|
|
/* Turn off CPU output */
|
2013-03-26 16:33:04 -07:00
|
|
|
val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
|
2011-09-22 12:01:57 -07:00
|
|
|
|
2013-03-26 16:33:04 -07:00
|
|
|
I915_WRITE(PCH_DREF_CONTROL, val);
|
2011-09-22 12:01:57 -07:00
|
|
|
POSTING_READ(PCH_DREF_CONTROL);
|
|
|
|
|
udelay(200);
|
|
|
|
|
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
if (!using_ssc_source) {
|
|
|
|
|
DRM_DEBUG_KMS("Disabling SSC source\n");
|
2011-09-22 12:01:57 -07:00
|
|
|
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
/* Turn off the SSC source */
|
|
|
|
|
val &= ~DREF_SSC_SOURCE_MASK;
|
|
|
|
|
val |= DREF_SSC_SOURCE_DISABLE;
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1464199863-9397-1-git-send-email-cpaul@redhat.com
2016-05-25 14:11:02 -04:00
|
|
|
|
drm/i915/ilk: Don't disable SSC source if it's in use
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
Unfortunately one of the sideaffects of having the refclk for a DPLL set
to SSC is that as long as it's set to SSC, the GPU will prevent us from
powering down any of the pipes or transcoders using it. A couple of
BIOSes enable SSC in both PCH_DREF_CONTROL and in the DPLL
configurations. This causes issues on the first modeset, since we don't
expect SSC to be left on and as a result, can't successfully power down
the pipes or the transcoders using it. Here's an example from this Dell
OptiPlex 990:
[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config] FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config] scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v4:
- Fix calculation of final for systems with LVDS panels (fixes BUG() on
CI test suite)
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.com
2016-06-14 11:04:09 -04:00
|
|
|
/* Turn off SSC1 */
|
|
|
|
|
val &= ~DREF_SSC1_ENABLE;
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PCH_DREF_CONTROL, val);
|
|
|
|
|
POSTING_READ(PCH_DREF_CONTROL);
|
|
|
|
|
udelay(200);
|
|
|
|
|
}
|
2011-08-03 12:59:20 -07:00
|
|
|
}
|
2013-03-26 16:33:04 -07:00
|
|
|
|
|
|
|
|
BUG_ON(val != final);
|
2011-08-03 12:59:20 -07:00
|
|
|
}
|
|
|
|
|
|
2013-07-18 18:51:11 -03:00
|
|
|
static void lpt_reset_fdi_mphy(struct drm_i915_private *dev_priv)
|
2012-12-01 12:04:25 -02:00
|
|
|
{
|
2013-07-18 18:51:11 -03:00
|
|
|
uint32_t tmp;
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = I915_READ(SOUTH_CHICKEN2);
|
|
|
|
|
tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
|
|
|
|
|
I915_WRITE(SOUTH_CHICKEN2, tmp);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2016-06-28 13:37:31 +03:00
|
|
|
if (wait_for_us(I915_READ(SOUTH_CHICKEN2) &
|
|
|
|
|
FDI_MPHY_IOSFSB_RESET_STATUS, 100))
|
2013-07-12 14:19:36 -03:00
|
|
|
DRM_ERROR("FDI mPHY reset assert timeout\n");
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = I915_READ(SOUTH_CHICKEN2);
|
|
|
|
|
tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
|
|
|
|
|
I915_WRITE(SOUTH_CHICKEN2, tmp);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2016-06-28 13:37:31 +03:00
|
|
|
if (wait_for_us((I915_READ(SOUTH_CHICKEN2) &
|
|
|
|
|
FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
|
2013-07-12 14:19:36 -03:00
|
|
|
DRM_ERROR("FDI mPHY reset de-assert timeout\n");
|
2013-07-18 18:51:11 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* WaMPhyProgramming:hsw */
|
|
|
|
|
static void lpt_program_fdi_mphy(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
uint32_t tmp;
|
2012-12-01 12:04:25 -02:00
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
|
|
|
|
|
tmp &= ~(0xFF << 24);
|
|
|
|
|
tmp |= (0x12 << 24);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
|
|
|
|
|
tmp |= (1 << 11);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
|
|
|
|
|
tmp |= (1 << 11);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
|
|
|
|
|
tmp |= (1 << 24) | (1 << 21) | (1 << 18);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
|
|
|
|
|
tmp |= (1 << 24) | (1 << 21) | (1 << 18);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
|
|
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
|
|
|
|
|
tmp &= ~(7 << 13);
|
|
|
|
|
tmp |= (5 << 13);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
|
|
|
|
|
tmp &= ~(7 << 13);
|
|
|
|
|
tmp |= (5 << 13);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
|
|
|
|
|
tmp &= ~0xFF;
|
|
|
|
|
tmp |= 0x1C;
|
|
|
|
|
intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
|
|
|
|
|
tmp &= ~0xFF;
|
|
|
|
|
tmp |= 0x1C;
|
|
|
|
|
intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
|
|
|
|
|
tmp &= ~(0xFF << 16);
|
|
|
|
|
tmp |= (0x1C << 16);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
|
|
|
|
|
tmp &= ~(0xFF << 16);
|
|
|
|
|
tmp |= (0x1C << 16);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
|
|
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
|
|
|
|
|
tmp |= (1 << 27);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
|
|
|
|
|
tmp |= (1 << 27);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
|
|
|
|
|
tmp &= ~(0xF << 28);
|
|
|
|
|
tmp |= (4 << 28);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2013-07-12 14:19:36 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
|
|
|
|
|
tmp &= ~(0xF << 28);
|
|
|
|
|
tmp |= (4 << 28);
|
|
|
|
|
intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
|
2013-07-18 18:51:11 -03:00
|
|
|
}
|
|
|
|
|
|
2013-07-23 11:19:24 -03:00
|
|
|
/* Implements 3 different sequences from BSpec chapter "Display iCLK
|
|
|
|
|
* Programming" based on the parameters passed:
|
|
|
|
|
* - Sequence to enable CLKOUT_DP
|
|
|
|
|
* - Sequence to enable CLKOUT_DP without spread
|
|
|
|
|
* - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O
|
|
|
|
|
*/
|
2016-11-23 16:21:44 +02:00
|
|
|
static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,
|
|
|
|
|
bool with_spread, bool with_fdi)
|
2013-07-18 18:51:11 -03:00
|
|
|
{
|
2013-07-23 11:19:24 -03:00
|
|
|
uint32_t reg, tmp;
|
|
|
|
|
|
|
|
|
|
if (WARN(with_fdi && !with_spread, "FDI requires downspread\n"))
|
|
|
|
|
with_spread = true;
|
2016-10-13 11:02:52 +01:00
|
|
|
if (WARN(HAS_PCH_LPT_LP(dev_priv) &&
|
|
|
|
|
with_fdi, "LP PCH doesn't have FDI\n"))
|
2013-07-23 11:19:24 -03:00
|
|
|
with_fdi = false;
|
2013-07-18 18:51:11 -03:00
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2013-07-18 18:51:11 -03:00
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
|
|
|
|
|
tmp &= ~SBI_SSCCTL_DISABLE;
|
|
|
|
|
tmp |= SBI_SSCCTL_PATHALT;
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
|
|
|
|
|
|
|
|
|
|
udelay(24);
|
|
|
|
|
|
2013-07-23 11:19:24 -03:00
|
|
|
if (with_spread) {
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
|
|
|
|
|
tmp &= ~SBI_SSCCTL_PATHALT;
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
|
2013-07-18 18:51:11 -03:00
|
|
|
|
2013-07-23 11:19:24 -03:00
|
|
|
if (with_fdi) {
|
|
|
|
|
lpt_reset_fdi_mphy(dev_priv);
|
|
|
|
|
lpt_program_fdi_mphy(dev_priv);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-12-01 12:04:25 -02:00
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
|
2013-07-23 11:19:24 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
|
|
|
|
|
tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
|
|
|
|
|
intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
|
2013-01-22 15:33:27 +01:00
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2012-12-01 12:04:25 -02:00
|
|
|
}
|
|
|
|
|
|
2013-07-23 11:19:25 -03:00
|
|
|
/* Sequence to disable CLKOUT_DP */
|
2016-11-23 16:21:44 +02:00
|
|
|
static void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
|
2013-07-23 11:19:25 -03:00
|
|
|
{
|
|
|
|
|
uint32_t reg, tmp;
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
2013-07-23 11:19:25 -03:00
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
|
2013-07-23 11:19:25 -03:00
|
|
|
tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
|
|
|
|
|
tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
|
|
|
|
|
intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
|
|
|
|
|
if (!(tmp & SBI_SSCCTL_DISABLE)) {
|
|
|
|
|
if (!(tmp & SBI_SSCCTL_PATHALT)) {
|
|
|
|
|
tmp |= SBI_SSCCTL_PATHALT;
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
|
|
|
|
|
udelay(32);
|
|
|
|
|
}
|
|
|
|
|
tmp |= SBI_SSCCTL_DISABLE;
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-26 20:42:30 +03:00
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
2013-07-23 11:19:25 -03:00
|
|
|
}
|
|
|
|
|
|
2015-12-04 22:19:39 +02:00
|
|
|
#define BEND_IDX(steps) ((50 + (steps)) / 5)
|
|
|
|
|
|
|
|
|
|
static const uint16_t sscdivintphase[] = {
|
|
|
|
|
[BEND_IDX( 50)] = 0x3B23,
|
|
|
|
|
[BEND_IDX( 45)] = 0x3B23,
|
|
|
|
|
[BEND_IDX( 40)] = 0x3C23,
|
|
|
|
|
[BEND_IDX( 35)] = 0x3C23,
|
|
|
|
|
[BEND_IDX( 30)] = 0x3D23,
|
|
|
|
|
[BEND_IDX( 25)] = 0x3D23,
|
|
|
|
|
[BEND_IDX( 20)] = 0x3E23,
|
|
|
|
|
[BEND_IDX( 15)] = 0x3E23,
|
|
|
|
|
[BEND_IDX( 10)] = 0x3F23,
|
|
|
|
|
[BEND_IDX( 5)] = 0x3F23,
|
|
|
|
|
[BEND_IDX( 0)] = 0x0025,
|
|
|
|
|
[BEND_IDX( -5)] = 0x0025,
|
|
|
|
|
[BEND_IDX(-10)] = 0x0125,
|
|
|
|
|
[BEND_IDX(-15)] = 0x0125,
|
|
|
|
|
[BEND_IDX(-20)] = 0x0225,
|
|
|
|
|
[BEND_IDX(-25)] = 0x0225,
|
|
|
|
|
[BEND_IDX(-30)] = 0x0325,
|
|
|
|
|
[BEND_IDX(-35)] = 0x0325,
|
|
|
|
|
[BEND_IDX(-40)] = 0x0425,
|
|
|
|
|
[BEND_IDX(-45)] = 0x0425,
|
|
|
|
|
[BEND_IDX(-50)] = 0x0525,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Bend CLKOUT_DP
|
|
|
|
|
* steps -50 to 50 inclusive, in steps of 5
|
|
|
|
|
* < 0 slow down the clock, > 0 speed up the clock, 0 == no bend (135MHz)
|
|
|
|
|
* change in clock period = -(steps / 10) * 5.787 ps
|
|
|
|
|
*/
|
|
|
|
|
static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
|
|
|
|
|
{
|
|
|
|
|
uint32_t tmp;
|
|
|
|
|
int idx = BEND_IDX(steps);
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(steps % 5 != 0))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(idx >= ARRAY_SIZE(sscdivintphase)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev_priv->sb_lock);
|
|
|
|
|
|
|
|
|
|
if (steps % 10 != 0)
|
|
|
|
|
tmp = 0xAAAAAAAB;
|
|
|
|
|
else
|
|
|
|
|
tmp = 0x00000000;
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCDITHPHASE, tmp, SBI_ICLK);
|
|
|
|
|
|
|
|
|
|
tmp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE, SBI_ICLK);
|
|
|
|
|
tmp &= 0xffff0000;
|
|
|
|
|
tmp |= sscdivintphase[idx];
|
|
|
|
|
intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE, tmp, SBI_ICLK);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dev_priv->sb_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef BEND_IDX
|
|
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
|
2013-07-12 14:19:38 -03:00
|
|
|
{
|
|
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
bool has_vga = false;
|
|
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
for_each_intel_encoder(&dev_priv->drm, encoder) {
|
2013-07-12 14:19:38 -03:00
|
|
|
switch (encoder->type) {
|
|
|
|
|
case INTEL_OUTPUT_ANALOG:
|
|
|
|
|
has_vga = true;
|
|
|
|
|
break;
|
2014-10-27 17:47:52 -02:00
|
|
|
default:
|
|
|
|
|
break;
|
2013-07-12 14:19:38 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-04 22:19:39 +02:00
|
|
|
if (has_vga) {
|
2016-11-23 16:21:44 +02:00
|
|
|
lpt_bend_clkout_dp(dev_priv, 0);
|
|
|
|
|
lpt_enable_clkout_dp(dev_priv, true, true);
|
2015-12-04 22:19:39 +02:00
|
|
|
} else {
|
2016-11-23 16:21:44 +02:00
|
|
|
lpt_disable_clkout_dp(dev_priv);
|
2015-12-04 22:19:39 +02:00
|
|
|
}
|
2013-07-12 14:19:38 -03:00
|
|
|
}
|
|
|
|
|
|
2012-12-01 12:04:25 -02:00
|
|
|
/*
|
|
|
|
|
* Initialize reference clocks when the driver loads
|
|
|
|
|
*/
|
2016-11-23 16:21:44 +02:00
|
|
|
void intel_init_pch_refclk(struct drm_i915_private *dev_priv)
|
2012-12-01 12:04:25 -02:00
|
|
|
{
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
ironlake_init_pch_refclk(dev_priv);
|
2016-10-13 11:02:53 +01:00
|
|
|
else if (HAS_PCH_LPT(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
lpt_init_pch_refclk(dev_priv);
|
2012-12-01 12:04:25 -02:00
|
|
|
}
|
|
|
|
|
|
2013-04-19 11:24:36 +02:00
|
|
|
static void ironlake_set_pipeconf(struct drm_crtc *crtc)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
int pipe = intel_crtc->pipe;
|
2012-09-12 10:06:29 -03:00
|
|
|
uint32_t val;
|
|
|
|
|
|
2013-06-13 00:54:57 +02:00
|
|
|
val = 0;
|
2012-09-12 10:06:29 -03:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
switch (intel_crtc->config->pipe_bpp) {
|
2012-09-12 10:06:29 -03:00
|
|
|
case 18:
|
2012-12-17 11:21:38 +01:00
|
|
|
val |= PIPECONF_6BPC;
|
2012-09-12 10:06:29 -03:00
|
|
|
break;
|
|
|
|
|
case 24:
|
2012-12-17 11:21:38 +01:00
|
|
|
val |= PIPECONF_8BPC;
|
2012-09-12 10:06:29 -03:00
|
|
|
break;
|
|
|
|
|
case 30:
|
2012-12-17 11:21:38 +01:00
|
|
|
val |= PIPECONF_10BPC;
|
2012-09-12 10:06:29 -03:00
|
|
|
break;
|
|
|
|
|
case 36:
|
2012-12-17 11:21:38 +01:00
|
|
|
val |= PIPECONF_12BPC;
|
2012-09-12 10:06:29 -03:00
|
|
|
break;
|
|
|
|
|
default:
|
2012-09-20 18:36:03 -03:00
|
|
|
/* Case prevented by intel_choose_pipe_bpp_dither. */
|
|
|
|
|
BUG();
|
2012-09-12 10:06:29 -03:00
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->dither)
|
2012-09-12 10:06:29 -03:00
|
|
|
val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
|
2012-09-12 10:06:29 -03:00
|
|
|
val |= PIPECONF_INTERLACED_ILK;
|
|
|
|
|
else
|
|
|
|
|
val |= PIPECONF_PROGRESSIVE;
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->limited_color_range)
|
2013-01-17 16:31:28 +02:00
|
|
|
val |= PIPECONF_COLOR_RANGE_SELECT;
|
|
|
|
|
|
2012-09-12 10:06:29 -03:00
|
|
|
I915_WRITE(PIPECONF(pipe), val);
|
|
|
|
|
POSTING_READ(PIPECONF(pipe));
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-19 11:24:36 +02:00
|
|
|
static void haswell_set_pipeconf(struct drm_crtc *crtc)
|
2012-10-05 12:05:57 -03:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2012-10-05 12:05:57 -03:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2015-01-15 14:55:25 +02:00
|
|
|
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
|
2016-03-18 17:05:40 +02:00
|
|
|
u32 val = 0;
|
2012-10-05 12:05:57 -03:00
|
|
|
|
2016-03-18 17:05:40 +02:00
|
|
|
if (IS_HASWELL(dev_priv) && intel_crtc->config->dither)
|
2012-10-05 12:05:57 -03:00
|
|
|
val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
|
2012-10-05 12:05:57 -03:00
|
|
|
val |= PIPECONF_INTERLACED_ILK;
|
|
|
|
|
else
|
|
|
|
|
val |= PIPECONF_PROGRESSIVE;
|
|
|
|
|
|
2012-10-23 18:29:59 -02:00
|
|
|
I915_WRITE(PIPECONF(cpu_transcoder), val);
|
|
|
|
|
POSTING_READ(PIPECONF(cpu_transcoder));
|
2016-03-18 17:05:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void haswell_set_pipemisc(struct drm_crtc *crtc)
|
|
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2016-03-18 17:05:40 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2017-07-24 19:19:32 +05:30
|
|
|
struct intel_crtc_state *config = intel_crtc->config;
|
2013-11-02 21:07:38 -07:00
|
|
|
|
2018-02-09 21:58:46 +00:00
|
|
|
if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
|
2016-03-18 17:05:40 +02:00
|
|
|
u32 val = 0;
|
2013-11-02 21:07:38 -07:00
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
switch (intel_crtc->config->pipe_bpp) {
|
2013-11-02 21:07:38 -07:00
|
|
|
case 18:
|
|
|
|
|
val |= PIPEMISC_DITHER_6_BPC;
|
|
|
|
|
break;
|
|
|
|
|
case 24:
|
|
|
|
|
val |= PIPEMISC_DITHER_8_BPC;
|
|
|
|
|
break;
|
|
|
|
|
case 30:
|
|
|
|
|
val |= PIPEMISC_DITHER_10_BPC;
|
|
|
|
|
break;
|
|
|
|
|
case 36:
|
|
|
|
|
val |= PIPEMISC_DITHER_12_BPC;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Case prevented by pipe_config_set_bpp. */
|
|
|
|
|
BUG();
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:25 +02:00
|
|
|
if (intel_crtc->config->dither)
|
2013-11-02 21:07:38 -07:00
|
|
|
val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
|
|
|
|
|
|
2017-07-24 19:19:32 +05:30
|
|
|
if (config->ycbcr420) {
|
|
|
|
|
val |= PIPEMISC_OUTPUT_COLORSPACE_YUV |
|
|
|
|
|
PIPEMISC_YUV420_ENABLE |
|
|
|
|
|
PIPEMISC_YUV420_MODE_FULL_BLEND;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:05:40 +02:00
|
|
|
I915_WRITE(PIPEMISC(intel_crtc->pipe), val);
|
2013-11-02 21:07:38 -07:00
|
|
|
}
|
2012-10-05 12:05:57 -03:00
|
|
|
}
|
|
|
|
|
|
2012-11-29 11:29:32 -02:00
|
|
|
int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Account for spread spectrum to avoid
|
|
|
|
|
* oversubscribing the link. Max center spread
|
|
|
|
|
* is 2.5%; use 5% for safety's sake.
|
|
|
|
|
*/
|
|
|
|
|
u32 bps = target_clock * bpp * 21 / 20;
|
2014-02-27 14:23:14 +02:00
|
|
|
return DIV_ROUND_UP(bps, link_bw * 8);
|
2012-11-29 11:29:32 -02:00
|
|
|
}
|
|
|
|
|
|
2013-04-20 17:19:46 +02:00
|
|
|
static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor)
|
drm/i915: clear up the fdi/dp set_m_n confusion
There's a rather decent confusion going on around transcoder m_n
values. So let's clarify:
- All dp encoders need this, either on the pch transcoder if it's a
pch port, or on the cpu transcoder/pipe if it's a cpu port.
- fdi links need to have the right m_n values for the fdi link set in
the cpu transcoder.
To handle the pch vs transcoder stuff a bit better, extract transcoder
set_m_n helpers. To make them simpler, set intel_crtc->cpu_transcoder
als in ironlake_crtc_mode_set, so that gen5+ (where the cpu m_n
registers are all at the same offset) can use it.
Haswell modeset is decently confused about dp vs. edp vs. fdi. dp vs.
edp works exactly the same as dp (since there's no pch dp any more),
so use that as a check. And only set up the fdi m_n values if we
really have a pch encoder present (which means we have a VGA encoder).
On ilk+ we've called ironlake_set_m_n both for cpu_edp and for pch
encoders. Now that dp_set_m_n handles all dp links (thanks to the
pch encoder check), we can ditch the cpu_edp stuff from the
fdi_set_m_n function.
Since the dp_m_n values are not readily available, we need to
carefully coax the edp values out of the encoder. Hence we can't (yet)
kill this superflous complexity.
v2: Rebase on top of the ivb fdi B/C check patch - we need to properly
clear intel_crtc->fdi_lane, otherwise those checks will misfire.
v3: Rebased on top of a s/IS_HASWELL/HAS_DDI/ patch from Paulo Zanoni.
v4: Drop the addition of has_dp_encoder, it's in the wrong patch (Jesse).
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-04-02 23:38:10 +02:00
|
|
|
{
|
2013-04-20 17:19:46 +02:00
|
|
|
return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
|
2012-09-20 18:36:04 -03:00
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:11 +02:00
|
|
|
static void ironlake_compute_dpll(struct intel_crtc *intel_crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state,
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll *reduced_clock)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2012-09-20 18:36:05 -03:00
|
|
|
struct drm_crtc *crtc = &intel_crtc->base;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-21 18:00:11 +02:00
|
|
|
u32 dpll, fp, fp2;
|
2016-06-22 21:57:03 +03:00
|
|
|
int factor;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2010-12-03 21:35:48 +00:00
|
|
|
/* Enable autotuning of the PLL clock (if permissible) */
|
2011-03-30 13:01:07 -07:00
|
|
|
factor = 21;
|
2016-06-22 21:57:03 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2011-03-30 13:01:07 -07:00
|
|
|
if ((intel_panel_use_ssc(dev_priv) &&
|
2013-12-09 18:54:16 +02:00
|
|
|
dev_priv->vbt.lvds_ssc_freq == 100000) ||
|
2016-10-13 11:02:53 +01:00
|
|
|
(HAS_PCH_IBX(dev_priv) && intel_is_dual_link_lvds(dev)))
|
2011-03-30 13:01:07 -07:00
|
|
|
factor = 25;
|
2015-01-15 14:55:23 +02:00
|
|
|
} else if (crtc_state->sdvo_tv_clock)
|
2011-03-30 13:01:07 -07:00
|
|
|
factor = 20;
|
2010-12-03 21:35:48 +00:00
|
|
|
|
2016-03-21 18:00:11 +02:00
|
|
|
fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
|
|
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
if (ironlake_needs_fb_cb_tune(&crtc_state->dpll, factor))
|
2016-03-21 18:00:11 +02:00
|
|
|
fp |= FP_CB_TUNE;
|
|
|
|
|
|
|
|
|
|
if (reduced_clock) {
|
|
|
|
|
fp2 = i9xx_dpll_compute_fp(reduced_clock);
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2016-03-21 18:00:11 +02:00
|
|
|
if (reduced_clock->m < factor * reduced_clock->n)
|
|
|
|
|
fp2 |= FP_CB_TUNE;
|
|
|
|
|
} else {
|
|
|
|
|
fp2 = fp;
|
|
|
|
|
}
|
2013-04-04 22:20:34 +02:00
|
|
|
|
2010-09-11 13:48:45 +01:00
|
|
|
dpll = 0;
|
2009-06-05 15:38:42 +08:00
|
|
|
|
2016-06-22 21:57:03 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
|
2011-03-30 13:01:08 -07:00
|
|
|
dpll |= DPLLB_MODE_LVDS;
|
|
|
|
|
else
|
|
|
|
|
dpll |= DPLLB_MODE_DAC_SERIAL;
|
2013-04-19 11:14:37 +02:00
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
dpll |= (crtc_state->pixel_multiplier - 1)
|
2013-06-01 17:17:04 +02:00
|
|
|
<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
|
2013-04-19 11:14:37 +02:00
|
|
|
|
2016-06-22 21:57:03 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
|
|
|
|
|
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
2013-07-06 12:52:05 +02:00
|
|
|
dpll |= DPLL_SDVO_HIGH_SPEED;
|
2016-06-22 21:57:03 +03:00
|
|
|
|
2016-06-22 21:57:04 +03:00
|
|
|
if (intel_crtc_has_dp_encoder(crtc_state))
|
2013-07-06 12:52:05 +02:00
|
|
|
dpll |= DPLL_SDVO_HIGH_SPEED;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-09-26 11:30:46 +03:00
|
|
|
/*
|
|
|
|
|
* The high speed IO clock is only really required for
|
|
|
|
|
* SDVO/HDMI/DP, but we also enable it for CRT to make it
|
|
|
|
|
* possible to share the DPLL between CRT and HDMI. Enabling
|
|
|
|
|
* the clock needlessly does no real harm, except use up a
|
|
|
|
|
* bit of power potentially.
|
|
|
|
|
*
|
|
|
|
|
* We'll limit this to IVB with 3 pipes, since it has only two
|
|
|
|
|
* DPLLs and so DPLL sharing is the only way to get three pipes
|
|
|
|
|
* driving PCH ports at the same time. On SNB we could do this,
|
|
|
|
|
* and potentially avoid enabling the second DPLL, but it's not
|
|
|
|
|
* clear if it''s a win or loss power wise. No point in doing
|
|
|
|
|
* this on ILK at all since it has a fixed DPLL<->pipe mapping.
|
|
|
|
|
*/
|
|
|
|
|
if (INTEL_INFO(dev_priv)->num_pipes == 3 &&
|
|
|
|
|
intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
|
|
|
|
|
dpll |= DPLL_SDVO_HIGH_SPEED;
|
|
|
|
|
|
2011-03-30 13:01:08 -07:00
|
|
|
/* compute bitmask from p1 value */
|
2015-01-15 14:55:23 +02:00
|
|
|
dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
|
2011-03-30 13:01:08 -07:00
|
|
|
/* also FPA1 */
|
2015-01-15 14:55:23 +02:00
|
|
|
dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
|
2011-03-30 13:01:08 -07:00
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
switch (crtc_state->dpll.p2) {
|
2011-03-30 13:01:08 -07:00
|
|
|
case 5:
|
|
|
|
|
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
|
|
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
|
|
|
|
|
break;
|
|
|
|
|
case 14:
|
|
|
|
|
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
|
|
|
|
|
break;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2016-06-22 21:57:03 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
|
|
|
|
|
intel_panel_use_ssc(dev_priv))
|
2009-02-13 20:56:52 -05:00
|
|
|
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
else
|
|
|
|
|
dpll |= PLL_REF_INPUT_DREFCLK;
|
|
|
|
|
|
2016-03-21 18:00:11 +02:00
|
|
|
dpll |= DPLL_VCO_ENABLE;
|
|
|
|
|
|
|
|
|
|
crtc_state->dpll_hw_state.dpll = dpll;
|
|
|
|
|
crtc_state->dpll_hw_state.fp0 = fp;
|
|
|
|
|
crtc_state->dpll_hw_state.fp1 = fp2;
|
2012-09-20 18:36:05 -03:00
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
2012-09-20 18:36:05 -03:00
|
|
|
{
|
2016-03-21 18:00:12 +02:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-04 12:11:59 +03:00
|
|
|
const struct intel_limit *limit;
|
2016-03-21 18:00:12 +02:00
|
|
|
int refclk = 120000;
|
2012-09-20 18:36:05 -03:00
|
|
|
|
2015-05-15 13:34:29 +03:00
|
|
|
memset(&crtc_state->dpll_hw_state, 0,
|
|
|
|
|
sizeof(crtc_state->dpll_hw_state));
|
|
|
|
|
|
2016-03-21 18:00:09 +02:00
|
|
|
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
|
|
|
|
|
if (!crtc_state->has_pch_encoder)
|
|
|
|
|
return 0;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-06-22 21:57:02 +03:00
|
|
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
|
2016-03-21 18:00:12 +02:00
|
|
|
if (intel_panel_use_ssc(dev_priv)) {
|
|
|
|
|
DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n",
|
|
|
|
|
dev_priv->vbt.lvds_ssc_freq);
|
|
|
|
|
refclk = dev_priv->vbt.lvds_ssc_freq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (intel_is_dual_link_lvds(dev)) {
|
|
|
|
|
if (refclk == 100000)
|
|
|
|
|
limit = &intel_limits_ironlake_dual_lvds_100m;
|
|
|
|
|
else
|
|
|
|
|
limit = &intel_limits_ironlake_dual_lvds;
|
|
|
|
|
} else {
|
|
|
|
|
if (refclk == 100000)
|
|
|
|
|
limit = &intel_limits_ironlake_single_lvds_100m;
|
|
|
|
|
else
|
|
|
|
|
limit = &intel_limits_ironlake_single_lvds;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
limit = &intel_limits_ironlake_dac;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 18:00:10 +02:00
|
|
|
if (!crtc_state->clock_set &&
|
2016-03-21 18:00:12 +02:00
|
|
|
!g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
|
|
|
|
|
refclk, NULL, &crtc_state->dpll)) {
|
2016-03-21 18:00:10 +02:00
|
|
|
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
|
|
|
|
return -EINVAL;
|
2013-03-28 10:42:02 +01:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-05-15 16:56:05 -05:00
|
|
|
ironlake_compute_dpll(crtc, crtc_state, NULL);
|
2013-06-05 13:34:20 +02:00
|
|
|
|
2017-05-15 17:00:28 -05:00
|
|
|
if (!intel_get_shared_dpll(crtc, crtc_state, NULL)) {
|
2016-03-21 18:00:09 +02:00
|
|
|
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
|
|
|
|
|
pipe_name(crtc->pipe));
|
|
|
|
|
return -EINVAL;
|
2014-10-29 11:32:35 +02:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2014-04-24 23:55:04 +02:00
|
|
|
return 0;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2013-09-10 17:02:54 +03:00
|
|
|
static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_link_m_n *m_n)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-09-10 17:02:54 +03:00
|
|
|
enum pipe pipe = crtc->pipe;
|
|
|
|
|
|
|
|
|
|
m_n->link_m = I915_READ(PCH_TRANS_LINK_M1(pipe));
|
|
|
|
|
m_n->link_n = I915_READ(PCH_TRANS_LINK_N1(pipe));
|
|
|
|
|
m_n->gmch_m = I915_READ(PCH_TRANS_DATA_M1(pipe))
|
|
|
|
|
& ~TU_SIZE_MASK;
|
|
|
|
|
m_n->gmch_n = I915_READ(PCH_TRANS_DATA_N1(pipe));
|
|
|
|
|
m_n->tu = ((I915_READ(PCH_TRANS_DATA_M1(pipe))
|
|
|
|
|
& TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
|
|
|
|
|
enum transcoder transcoder,
|
2014-08-05 07:51:23 -07:00
|
|
|
struct intel_link_m_n *m_n,
|
|
|
|
|
struct intel_link_m_n *m2_n2)
|
2013-04-04 13:28:53 +02:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2013-09-10 17:02:54 +03:00
|
|
|
enum pipe pipe = crtc->pipe;
|
2013-04-04 13:28:53 +02:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 5) {
|
2013-09-10 17:02:54 +03:00
|
|
|
m_n->link_m = I915_READ(PIPE_LINK_M1(transcoder));
|
|
|
|
|
m_n->link_n = I915_READ(PIPE_LINK_N1(transcoder));
|
|
|
|
|
m_n->gmch_m = I915_READ(PIPE_DATA_M1(transcoder))
|
|
|
|
|
& ~TU_SIZE_MASK;
|
|
|
|
|
m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
|
|
|
|
|
m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder))
|
|
|
|
|
& TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
|
2014-08-05 07:51:23 -07:00
|
|
|
/* Read M2_N2 registers only for gen < 8 (M2_N2 available for
|
|
|
|
|
* gen < 8) and if DRRS is supported (to make sure the
|
|
|
|
|
* registers are not unnecessarily read).
|
|
|
|
|
*/
|
2016-11-16 12:32:42 +00:00
|
|
|
if (m2_n2 && INTEL_GEN(dev_priv) < 8 &&
|
2015-01-15 14:55:25 +02:00
|
|
|
crtc->config->has_drrs) {
|
2014-08-05 07:51:23 -07:00
|
|
|
m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder));
|
|
|
|
|
m2_n2->link_n = I915_READ(PIPE_LINK_N2(transcoder));
|
|
|
|
|
m2_n2->gmch_m = I915_READ(PIPE_DATA_M2(transcoder))
|
|
|
|
|
& ~TU_SIZE_MASK;
|
|
|
|
|
m2_n2->gmch_n = I915_READ(PIPE_DATA_N2(transcoder));
|
|
|
|
|
m2_n2->tu = ((I915_READ(PIPE_DATA_M2(transcoder))
|
|
|
|
|
& TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
|
|
|
|
|
}
|
2013-09-10 17:02:54 +03:00
|
|
|
} else {
|
|
|
|
|
m_n->link_m = I915_READ(PIPE_LINK_M_G4X(pipe));
|
|
|
|
|
m_n->link_n = I915_READ(PIPE_LINK_N_G4X(pipe));
|
|
|
|
|
m_n->gmch_m = I915_READ(PIPE_DATA_M_G4X(pipe))
|
|
|
|
|
& ~TU_SIZE_MASK;
|
|
|
|
|
m_n->gmch_n = I915_READ(PIPE_DATA_N_G4X(pipe));
|
|
|
|
|
m_n->tu = ((I915_READ(PIPE_DATA_M_G4X(pipe))
|
|
|
|
|
& TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void intel_dp_get_m_n(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-09-10 17:02:54 +03:00
|
|
|
{
|
2015-01-15 14:55:24 +02:00
|
|
|
if (pipe_config->has_pch_encoder)
|
2013-09-10 17:02:54 +03:00
|
|
|
intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n);
|
|
|
|
|
else
|
|
|
|
|
intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
|
2014-08-05 07:51:23 -07:00
|
|
|
&pipe_config->dp_m_n,
|
|
|
|
|
&pipe_config->dp_m2_n2);
|
2013-09-10 17:02:54 +03:00
|
|
|
}
|
2013-04-04 13:28:53 +02:00
|
|
|
|
2013-09-10 17:02:54 +03:00
|
|
|
static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-09-10 17:02:54 +03:00
|
|
|
{
|
|
|
|
|
intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
|
2014-08-05 07:51:23 -07:00
|
|
|
&pipe_config->fdi_m_n, NULL);
|
2013-04-04 13:28:53 +02:00
|
|
|
}
|
|
|
|
|
|
2014-11-13 17:51:47 +00:00
|
|
|
static void skylake_get_pfit_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-11-13 17:51:47 +00:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-04-07 15:28:45 -07:00
|
|
|
struct intel_crtc_scaler_state *scaler_state = &pipe_config->scaler_state;
|
|
|
|
|
uint32_t ps_ctrl = 0;
|
|
|
|
|
int id = -1;
|
|
|
|
|
int i;
|
2014-11-13 17:51:47 +00:00
|
|
|
|
2015-04-07 15:28:45 -07:00
|
|
|
/* find scaler attached to this pipe */
|
|
|
|
|
for (i = 0; i < crtc->num_scalers; i++) {
|
|
|
|
|
ps_ctrl = I915_READ(SKL_PS_CTRL(crtc->pipe, i));
|
|
|
|
|
if (ps_ctrl & PS_SCALER_EN && !(ps_ctrl & PS_PLANE_SEL_MASK)) {
|
|
|
|
|
id = i;
|
|
|
|
|
pipe_config->pch_pfit.enabled = true;
|
|
|
|
|
pipe_config->pch_pfit.pos = I915_READ(SKL_PS_WIN_POS(crtc->pipe, i));
|
|
|
|
|
pipe_config->pch_pfit.size = I915_READ(SKL_PS_WIN_SZ(crtc->pipe, i));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-13 17:51:47 +00:00
|
|
|
|
2015-04-07 15:28:45 -07:00
|
|
|
scaler_state->scaler_id = id;
|
|
|
|
|
if (id >= 0) {
|
|
|
|
|
scaler_state->scaler_users |= (1 << SKL_CRTC_INDEX);
|
|
|
|
|
} else {
|
|
|
|
|
scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX);
|
2014-11-13 17:51:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:52 +00:00
|
|
|
static void
|
|
|
|
|
skylake_get_initial_plane_config(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_initial_plane_config *plane_config)
|
2015-01-20 12:51:51 +00:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-11-17 21:19:12 +02:00
|
|
|
struct intel_plane *plane = to_intel_plane(crtc->base.primary);
|
|
|
|
|
enum plane_id plane_id = plane->id;
|
|
|
|
|
enum pipe pipe = crtc->pipe;
|
2017-11-13 10:11:28 -08:00
|
|
|
u32 val, base, offset, stride_mult, tiling, alpha;
|
2015-01-20 12:51:51 +00:00
|
|
|
int fourcc, pixel_format;
|
2015-03-23 11:10:32 +00:00
|
|
|
unsigned int aligned_height;
|
2015-01-20 12:51:51 +00:00
|
|
|
struct drm_framebuffer *fb;
|
2015-01-21 13:50:54 +00:00
|
|
|
struct intel_framebuffer *intel_fb;
|
2015-01-20 12:51:51 +00:00
|
|
|
|
2017-11-17 21:19:16 +02:00
|
|
|
if (!plane->get_hw_state(plane))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-21 14:07:19 +00:00
|
|
|
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
|
2015-01-21 13:50:54 +00:00
|
|
|
if (!intel_fb) {
|
2015-01-20 12:51:51 +00:00
|
|
|
DRM_DEBUG_KMS("failed to alloc fb\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 13:50:54 +00:00
|
|
|
fb = &intel_fb->base;
|
|
|
|
|
|
2016-11-18 21:52:53 +02:00
|
|
|
fb->dev = dev;
|
|
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
val = I915_READ(PLANE_CTL(pipe, plane_id));
|
2015-02-05 19:35:13 +00:00
|
|
|
|
2018-01-30 11:49:16 -02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 11)
|
|
|
|
|
pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK;
|
|
|
|
|
else
|
|
|
|
|
pixel_format = val & PLANE_CTL_FORMAT_MASK;
|
2017-11-13 10:11:28 -08:00
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
|
2017-11-17 21:19:12 +02:00
|
|
|
alpha = I915_READ(PLANE_COLOR_CTL(pipe, plane_id));
|
2017-11-13 10:11:28 -08:00
|
|
|
alpha &= PLANE_COLOR_ALPHA_MASK;
|
|
|
|
|
} else {
|
|
|
|
|
alpha = val & PLANE_CTL_ALPHA_MASK;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-20 12:51:51 +00:00
|
|
|
fourcc = skl_format_to_fourcc(pixel_format,
|
2017-11-13 10:11:28 -08:00
|
|
|
val & PLANE_CTL_ORDER_RGBX, alpha);
|
2016-11-18 21:52:57 +02:00
|
|
|
fb->format = drm_format_info(fourcc);
|
2015-01-20 12:51:51 +00:00
|
|
|
|
2015-02-27 11:15:21 +00:00
|
|
|
tiling = val & PLANE_CTL_TILED_MASK;
|
|
|
|
|
switch (tiling) {
|
|
|
|
|
case PLANE_CTL_TILED_LINEAR:
|
2017-03-24 14:29:48 -07:00
|
|
|
fb->modifier = DRM_FORMAT_MOD_LINEAR;
|
2015-02-27 11:15:21 +00:00
|
|
|
break;
|
|
|
|
|
case PLANE_CTL_TILED_X:
|
|
|
|
|
plane_config->tiling = I915_TILING_X;
|
2016-11-16 13:33:16 +02:00
|
|
|
fb->modifier = I915_FORMAT_MOD_X_TILED;
|
2015-02-27 11:15:21 +00:00
|
|
|
break;
|
|
|
|
|
case PLANE_CTL_TILED_Y:
|
2017-08-01 09:58:13 -07:00
|
|
|
if (val & PLANE_CTL_DECOMPRESSION_ENABLE)
|
|
|
|
|
fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
|
|
|
|
|
else
|
|
|
|
|
fb->modifier = I915_FORMAT_MOD_Y_TILED;
|
2015-02-27 11:15:21 +00:00
|
|
|
break;
|
|
|
|
|
case PLANE_CTL_TILED_YF:
|
2017-08-01 09:58:13 -07:00
|
|
|
if (val & PLANE_CTL_DECOMPRESSION_ENABLE)
|
|
|
|
|
fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
|
|
|
|
|
else
|
|
|
|
|
fb->modifier = I915_FORMAT_MOD_Yf_TILED;
|
2015-02-27 11:15:21 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
MISSING_CASE(tiling);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
base = I915_READ(PLANE_SURF(pipe, plane_id)) & 0xfffff000;
|
2015-01-20 12:51:51 +00:00
|
|
|
plane_config->base = base;
|
|
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
offset = I915_READ(PLANE_OFFSET(pipe, plane_id));
|
2015-01-20 12:51:51 +00:00
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
val = I915_READ(PLANE_SIZE(pipe, plane_id));
|
2015-01-20 12:51:51 +00:00
|
|
|
fb->height = ((val >> 16) & 0xfff) + 1;
|
|
|
|
|
fb->width = ((val >> 0) & 0x1fff) + 1;
|
|
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
val = I915_READ(PLANE_STRIDE(pipe, plane_id));
|
2017-03-07 21:42:06 +02:00
|
|
|
stride_mult = intel_fb_stride_alignment(fb, 0);
|
2015-01-20 12:51:51 +00:00
|
|
|
fb->pitches[0] = (val & 0x3ff) * stride_mult;
|
|
|
|
|
|
2017-03-07 21:42:06 +02:00
|
|
|
aligned_height = intel_fb_align_height(fb, 0, fb->height);
|
2015-01-20 12:51:51 +00:00
|
|
|
|
2015-02-10 23:12:27 +01:00
|
|
|
plane_config->size = fb->pitches[0] * aligned_height;
|
2015-01-20 12:51:51 +00:00
|
|
|
|
2017-11-17 21:19:12 +02:00
|
|
|
DRM_DEBUG_KMS("%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
|
|
|
|
|
crtc->base.name, plane->base.name, fb->width, fb->height,
|
2016-12-14 23:32:20 +02:00
|
|
|
fb->format->cpp[0] * 8, base, fb->pitches[0],
|
2015-01-20 12:51:51 +00:00
|
|
|
plane_config->size);
|
|
|
|
|
|
2015-02-05 17:22:18 +00:00
|
|
|
plane_config->fb = intel_fb;
|
2015-01-20 12:51:51 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
error:
|
2016-08-23 16:00:44 +01:00
|
|
|
kfree(intel_fb);
|
2015-01-20 12:51:51 +00:00
|
|
|
}
|
|
|
|
|
|
2013-05-07 23:34:16 +02:00
|
|
|
static void ironlake_get_pfit_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-05-07 23:34:16 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-05-07 23:34:16 +02:00
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
|
|
tmp = I915_READ(PF_CTL(crtc->pipe));
|
|
|
|
|
|
|
|
|
|
if (tmp & PF_ENABLE) {
|
2013-08-27 17:04:17 +01:00
|
|
|
pipe_config->pch_pfit.enabled = true;
|
2013-05-07 23:34:16 +02:00
|
|
|
pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
|
|
|
|
|
pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
|
2013-06-01 17:16:23 +02:00
|
|
|
|
|
|
|
|
/* We currently do not free assignements of panel fitters on
|
|
|
|
|
* ivb/hsw (since we don't use the higher upscaling modes which
|
|
|
|
|
* differentiates them) so just WARN about this case for now. */
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN7(dev_priv)) {
|
2013-06-01 17:16:23 +02:00
|
|
|
WARN_ON((tmp & PF_PIPE_SEL_MASK_IVB) !=
|
|
|
|
|
PF_PIPE_SEL_IVB(crtc->pipe));
|
|
|
|
|
}
|
2013-05-07 23:34:16 +02:00
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2013-03-28 10:42:00 +01:00
|
|
|
static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-03-28 10:42:00 +01:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-02-12 18:55:11 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
2013-03-28 10:42:00 +01:00
|
|
|
uint32_t tmp;
|
2016-02-12 18:55:11 +02:00
|
|
|
bool ret;
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
2014-07-04 13:38:34 -03:00
|
|
|
return false;
|
|
|
|
|
|
2013-07-04 12:01:15 +02:00
|
|
|
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
|
2016-03-08 17:46:18 +02:00
|
|
|
pipe_config->shared_dpll = NULL;
|
2013-05-22 00:50:22 +02:00
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
ret = false;
|
2013-03-28 10:42:00 +01:00
|
|
|
tmp = I915_READ(PIPECONF(crtc->pipe));
|
|
|
|
|
if (!(tmp & PIPECONF_ENABLE))
|
2016-02-12 18:55:11 +02:00
|
|
|
goto out;
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2013-09-06 23:29:00 +03:00
|
|
|
switch (tmp & PIPECONF_BPC_MASK) {
|
|
|
|
|
case PIPECONF_6BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 18;
|
|
|
|
|
break;
|
|
|
|
|
case PIPECONF_8BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 24;
|
|
|
|
|
break;
|
|
|
|
|
case PIPECONF_10BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 30;
|
|
|
|
|
break;
|
|
|
|
|
case PIPECONF_12BPC:
|
|
|
|
|
pipe_config->pipe_bpp = 36;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-24 23:54:49 +02:00
|
|
|
if (tmp & PIPECONF_COLOR_RANGE_SELECT)
|
|
|
|
|
pipe_config->limited_color_range = true;
|
|
|
|
|
|
2013-05-03 11:49:46 +02:00
|
|
|
if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
|
2013-06-05 13:34:20 +02:00
|
|
|
struct intel_shared_dpll *pll;
|
2016-03-08 17:46:18 +02:00
|
|
|
enum intel_dpll_id pll_id;
|
2013-06-05 13:34:20 +02:00
|
|
|
|
2013-03-28 10:42:01 +01:00
|
|
|
pipe_config->has_pch_encoder = true;
|
|
|
|
|
|
2013-04-29 19:33:42 +02:00
|
|
|
tmp = I915_READ(FDI_RX_CTL(crtc->pipe));
|
|
|
|
|
pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >>
|
|
|
|
|
FDI_DP_PORT_WIDTH_SHIFT) + 1;
|
2013-04-04 13:28:53 +02:00
|
|
|
|
|
|
|
|
ironlake_get_fdi_m_n_config(crtc, pipe_config);
|
2013-06-06 12:45:25 +02:00
|
|
|
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_PCH_IBX(dev_priv)) {
|
2016-05-12 16:18:50 +03:00
|
|
|
/*
|
|
|
|
|
* The pipe->pch transcoder and pch transcoder->pll
|
|
|
|
|
* mapping is fixed.
|
|
|
|
|
*/
|
2016-03-08 17:46:18 +02:00
|
|
|
pll_id = (enum intel_dpll_id) crtc->pipe;
|
2013-06-07 23:11:08 +02:00
|
|
|
} else {
|
|
|
|
|
tmp = I915_READ(PCH_DPLL_SEL);
|
|
|
|
|
if (tmp & TRANS_DPLLB_SEL(crtc->pipe))
|
2016-03-08 17:46:18 +02:00
|
|
|
pll_id = DPLL_ID_PCH_PLL_B;
|
2013-06-07 23:11:08 +02:00
|
|
|
else
|
2016-03-08 17:46:18 +02:00
|
|
|
pll_id= DPLL_ID_PCH_PLL_A;
|
2013-06-07 23:11:08 +02:00
|
|
|
}
|
2013-06-05 13:34:20 +02:00
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
pipe_config->shared_dpll =
|
|
|
|
|
intel_get_shared_dpll_by_id(dev_priv, pll_id);
|
|
|
|
|
pll = pipe_config->shared_dpll;
|
2013-06-05 13:34:20 +02:00
|
|
|
|
2016-03-08 17:46:21 +02:00
|
|
|
WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
|
|
|
|
|
&pipe_config->dpll_hw_state));
|
2013-06-27 19:47:19 +02:00
|
|
|
|
|
|
|
|
tmp = pipe_config->dpll_hw_state.dpll;
|
|
|
|
|
pipe_config->pixel_multiplier =
|
|
|
|
|
((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK)
|
|
|
|
|
>> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1;
|
2013-09-13 16:00:08 +03:00
|
|
|
|
|
|
|
|
ironlake_pch_clock_get(crtc, pipe_config);
|
2013-06-06 12:45:25 +02:00
|
|
|
} else {
|
|
|
|
|
pipe_config->pixel_multiplier = 1;
|
2013-04-29 19:33:42 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 21:56:12 +02:00
|
|
|
intel_get_pipe_timings(crtc, pipe_config);
|
2016-03-18 17:05:39 +02:00
|
|
|
intel_get_pipe_src_size(crtc, pipe_config);
|
2013-04-29 21:56:12 +02:00
|
|
|
|
2013-05-07 23:34:16 +02:00
|
|
|
ironlake_get_pfit_config(crtc, pipe_config);
|
|
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
ret = true;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
|
|
|
|
|
return ret;
|
2013-03-28 10:42:00 +01:00
|
|
|
}
|
|
|
|
|
|
2013-07-23 11:19:26 -03:00
|
|
|
static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
2016-07-05 10:40:23 +01:00
|
|
|
struct drm_device *dev = &dev_priv->drm;
|
2013-07-23 11:19:26 -03:00
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
|
2014-05-13 23:32:22 +01:00
|
|
|
for_each_intel_crtc(dev, crtc)
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
|
2013-07-23 11:19:26 -03:00
|
|
|
pipe_name(crtc->pipe));
|
|
|
|
|
|
2017-08-14 18:15:30 +03:00
|
|
|
I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL)),
|
|
|
|
|
"Display power well on\n");
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
|
2015-09-18 20:03:33 +03:00
|
|
|
I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
|
|
|
|
|
I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
|
2016-08-10 14:07:29 +03:00
|
|
|
I915_STATE_WARN(I915_READ(PP_STATUS(0)) & PP_ON, "Panel power on\n");
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
|
2013-07-23 11:19:26 -03:00
|
|
|
"CPU PWM1 enabled\n");
|
2016-10-13 11:03:01 +01:00
|
|
|
if (IS_HASWELL(dev_priv))
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
|
2014-07-04 11:50:30 -03:00
|
|
|
"CPU PWM2 enabled\n");
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
|
2013-07-23 11:19:26 -03:00
|
|
|
"PCH PWM1 enabled\n");
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
|
2013-07-23 11:19:26 -03:00
|
|
|
"Utility pin enabled\n");
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
|
2013-07-23 11:19:26 -03:00
|
|
|
|
2014-04-01 19:39:47 -03:00
|
|
|
/*
|
|
|
|
|
* In theory we can still leave IRQs enabled, as long as only the HPD
|
|
|
|
|
* interrupts remain enabled. We used to check for that, but since it's
|
|
|
|
|
* gen-specific and since we only disable LCPLL after we fully disable
|
|
|
|
|
* the interrupts, the check below should be enough.
|
|
|
|
|
*/
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
|
2013-07-23 11:19:26 -03:00
|
|
|
}
|
|
|
|
|
|
2014-07-04 11:59:58 -03:00
|
|
|
static uint32_t hsw_read_dcomp(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
2016-10-13 11:03:01 +01:00
|
|
|
if (IS_HASWELL(dev_priv))
|
2014-07-04 11:59:58 -03:00
|
|
|
return I915_READ(D_COMP_HSW);
|
|
|
|
|
else
|
|
|
|
|
return I915_READ(D_COMP_BDW);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-07 20:12:36 -03:00
|
|
|
static void hsw_write_dcomp(struct drm_i915_private *dev_priv, uint32_t val)
|
|
|
|
|
{
|
2016-10-13 11:03:01 +01:00
|
|
|
if (IS_HASWELL(dev_priv)) {
|
2017-10-10 22:30:05 +01:00
|
|
|
mutex_lock(&dev_priv->pcu_lock);
|
2014-03-07 20:12:36 -03:00
|
|
|
if (sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_D_COMP,
|
|
|
|
|
val))
|
2016-08-24 11:16:07 +01:00
|
|
|
DRM_DEBUG_KMS("Failed to write to D_COMP\n");
|
2017-10-10 22:30:05 +01:00
|
|
|
mutex_unlock(&dev_priv->pcu_lock);
|
2014-03-07 20:12:36 -03:00
|
|
|
} else {
|
2014-07-04 11:59:58 -03:00
|
|
|
I915_WRITE(D_COMP_BDW, val);
|
|
|
|
|
POSTING_READ(D_COMP_BDW);
|
2014-03-07 20:12:36 -03:00
|
|
|
}
|
2013-07-23 11:19:26 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function implements pieces of two sequences from BSpec:
|
|
|
|
|
* - Sequence for display software to disable LCPLL
|
|
|
|
|
* - Sequence for display software to allow package C8+
|
|
|
|
|
* The steps implemented here are just the steps that actually touch the LCPLL
|
|
|
|
|
* register. Callers should take care of disabling all the display engine
|
|
|
|
|
* functions, doing the mode unset, fixing interrupts, etc.
|
|
|
|
|
*/
|
2013-09-24 13:52:57 -03:00
|
|
|
static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
|
|
|
|
|
bool switch_to_fclk, bool allow_power_down)
|
2013-07-23 11:19:26 -03:00
|
|
|
{
|
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
|
|
assert_can_disable_lcpll(dev_priv);
|
|
|
|
|
|
|
|
|
|
val = I915_READ(LCPLL_CTL);
|
|
|
|
|
|
|
|
|
|
if (switch_to_fclk) {
|
|
|
|
|
val |= LCPLL_CD_SOURCE_FCLK;
|
|
|
|
|
I915_WRITE(LCPLL_CTL, val);
|
|
|
|
|
|
2016-06-28 13:37:32 +03:00
|
|
|
if (wait_for_us(I915_READ(LCPLL_CTL) &
|
|
|
|
|
LCPLL_CD_SOURCE_FCLK_DONE, 1))
|
2013-07-23 11:19:26 -03:00
|
|
|
DRM_ERROR("Switching to FCLK failed\n");
|
|
|
|
|
|
|
|
|
|
val = I915_READ(LCPLL_CTL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val |= LCPLL_PLL_DISABLE;
|
|
|
|
|
I915_WRITE(LCPLL_CTL, val);
|
|
|
|
|
POSTING_READ(LCPLL_CTL);
|
|
|
|
|
|
2016-06-30 15:33:07 +01:00
|
|
|
if (intel_wait_for_register(dev_priv, LCPLL_CTL, LCPLL_PLL_LOCK, 0, 1))
|
2013-07-23 11:19:26 -03:00
|
|
|
DRM_ERROR("LCPLL still locked\n");
|
|
|
|
|
|
2014-07-04 11:59:58 -03:00
|
|
|
val = hsw_read_dcomp(dev_priv);
|
2013-07-23 11:19:26 -03:00
|
|
|
val |= D_COMP_COMP_DISABLE;
|
2014-03-07 20:12:36 -03:00
|
|
|
hsw_write_dcomp(dev_priv, val);
|
2013-07-23 11:19:26 -03:00
|
|
|
ndelay(100);
|
|
|
|
|
|
2014-07-04 11:59:58 -03:00
|
|
|
if (wait_for((hsw_read_dcomp(dev_priv) & D_COMP_RCOMP_IN_PROGRESS) == 0,
|
|
|
|
|
1))
|
2013-07-23 11:19:26 -03:00
|
|
|
DRM_ERROR("D_COMP RCOMP still in progress\n");
|
|
|
|
|
|
|
|
|
|
if (allow_power_down) {
|
|
|
|
|
val = I915_READ(LCPLL_CTL);
|
|
|
|
|
val |= LCPLL_POWER_DOWN_ALLOW;
|
|
|
|
|
I915_WRITE(LCPLL_CTL, val);
|
|
|
|
|
POSTING_READ(LCPLL_CTL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Fully restores LCPLL, disallowing power down and switching back to LCPLL
|
|
|
|
|
* source.
|
|
|
|
|
*/
|
2013-09-24 13:52:57 -03:00
|
|
|
static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
|
2013-07-23 11:19:26 -03:00
|
|
|
{
|
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
|
|
val = I915_READ(LCPLL_CTL);
|
|
|
|
|
|
|
|
|
|
if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK |
|
|
|
|
|
LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
|
|
|
|
|
return;
|
|
|
|
|
|
drm/i915: make PC8 be part of runtime PM suspend/resume
Currently, when our driver becomes idle for i915.pc8_timeout (default:
5s) we enable PC8, so we save some power, but not everything we can.
Then, while PC8 is enabled, if we stay idle for more
autosuspend_delay_ms (default: 10s) we'll enter runtime PM and put the
graphics device in D3 state, saving even more power. The two features
are separate things with increasing levels of power savings, but if we
disable PC8 we'll never get into D3.
While from the modularity point of view it would be nice to keep these
features as separate, we have reasons to merge them:
- We are not aware of anybody wanting a "PC8 without D3" environment.
- If we keep both features as separate, we'll have to to test both
PC8 and PC8+D3 code paths. We're already having a major pain to
make QA do automated testing of just one thing, testing both paths
will cost even more.
- Only Haswell+ supports PC8, so if we want to add runtime PM support
to, for example, IVB, we'll have to copy some code from the PC8
feature to runtime PM, so merging both features as a single thing
will make it easier for enabling runtime PM on other platforms.
This patch only does the very basic steps required to have PC8 and
runtime PM merged on a single feature: the next patches will take care
of cleaning up everything.
v2: - Rebase.
v3: - Rebase.
- Fully remove the deprecated i915 params since Daniel doesn't
consider them as part of the ABI.
v4: - Rebase.
- Fix typo in the commit message.
v5: - Rebase, again.
- Add a huge comment explaining the different forcewake usage
(Chris, Daniel).
- Use open-coded forcewake functions (Daniel).
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2014-03-07 20:08:05 -03:00
|
|
|
/*
|
|
|
|
|
* Make sure we're not on PC8 state before disabling PC8, otherwise
|
|
|
|
|
* we'll hang the machine. To prevent PC8 state, just enable force_wake.
|
|
|
|
|
*/
|
2015-01-16 11:34:40 +02:00
|
|
|
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
|
2013-08-19 13:18:07 -03:00
|
|
|
|
2013-07-23 11:19:26 -03:00
|
|
|
if (val & LCPLL_POWER_DOWN_ALLOW) {
|
|
|
|
|
val &= ~LCPLL_POWER_DOWN_ALLOW;
|
|
|
|
|
I915_WRITE(LCPLL_CTL, val);
|
2013-08-21 23:38:08 +02:00
|
|
|
POSTING_READ(LCPLL_CTL);
|
2013-07-23 11:19:26 -03:00
|
|
|
}
|
|
|
|
|
|
2014-07-04 11:59:58 -03:00
|
|
|
val = hsw_read_dcomp(dev_priv);
|
2013-07-23 11:19:26 -03:00
|
|
|
val |= D_COMP_COMP_FORCE;
|
|
|
|
|
val &= ~D_COMP_COMP_DISABLE;
|
2014-03-07 20:12:36 -03:00
|
|
|
hsw_write_dcomp(dev_priv, val);
|
2013-07-23 11:19:26 -03:00
|
|
|
|
|
|
|
|
val = I915_READ(LCPLL_CTL);
|
|
|
|
|
val &= ~LCPLL_PLL_DISABLE;
|
|
|
|
|
I915_WRITE(LCPLL_CTL, val);
|
|
|
|
|
|
2016-06-30 15:33:08 +01:00
|
|
|
if (intel_wait_for_register(dev_priv,
|
|
|
|
|
LCPLL_CTL, LCPLL_PLL_LOCK, LCPLL_PLL_LOCK,
|
|
|
|
|
5))
|
2013-07-23 11:19:26 -03:00
|
|
|
DRM_ERROR("LCPLL not locked yet\n");
|
|
|
|
|
|
|
|
|
|
if (val & LCPLL_CD_SOURCE_FCLK) {
|
|
|
|
|
val = I915_READ(LCPLL_CTL);
|
|
|
|
|
val &= ~LCPLL_CD_SOURCE_FCLK;
|
|
|
|
|
I915_WRITE(LCPLL_CTL, val);
|
|
|
|
|
|
2016-06-28 13:37:32 +03:00
|
|
|
if (wait_for_us((I915_READ(LCPLL_CTL) &
|
|
|
|
|
LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
|
2013-07-23 11:19:26 -03:00
|
|
|
DRM_ERROR("Switching back to LCPLL failed\n");
|
|
|
|
|
}
|
2013-08-19 13:18:07 -03:00
|
|
|
|
2015-01-16 11:34:40 +02:00
|
|
|
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
|
2017-10-24 12:52:16 +03:00
|
|
|
|
2016-10-31 22:37:12 +02:00
|
|
|
intel_update_cdclk(dev_priv);
|
2017-10-24 12:52:16 +03:00
|
|
|
intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
|
2013-07-23 11:19:26 -03:00
|
|
|
}
|
|
|
|
|
|
2014-03-07 20:08:18 -03:00
|
|
|
/*
|
|
|
|
|
* Package states C8 and deeper are really deep PC states that can only be
|
|
|
|
|
* reached when all the devices on the system allow it, so even if the graphics
|
|
|
|
|
* device allows PC8+, it doesn't mean the system will actually get to these
|
|
|
|
|
* states. Our driver only allows PC8+ when going into runtime PM.
|
|
|
|
|
*
|
|
|
|
|
* The requirements for PC8+ are that all the outputs are disabled, the power
|
|
|
|
|
* well is disabled and most interrupts are disabled, and these are also
|
|
|
|
|
* requirements for runtime PM. When these conditions are met, we manually do
|
|
|
|
|
* the other conditions: disable the interrupts, clocks and switch LCPLL refclk
|
|
|
|
|
* to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard
|
|
|
|
|
* hang the machine.
|
|
|
|
|
*
|
|
|
|
|
* When we really reach PC8 or deeper states (not just when we allow it) we lose
|
|
|
|
|
* the state of some registers, so when we come back from PC8+ we need to
|
|
|
|
|
* restore this state. We don't get into PC8+ if we're not in RC6, so we don't
|
|
|
|
|
* need to take care of the registers kept by RC6. Notice that this happens even
|
|
|
|
|
* if we don't put the device in PCI D3 state (which is what currently happens
|
|
|
|
|
* because of the runtime PM support).
|
|
|
|
|
*
|
|
|
|
|
* For more, read "Display Sequences for Package C8" on the hardware
|
|
|
|
|
* documentation.
|
|
|
|
|
*/
|
2014-03-07 20:08:17 -03:00
|
|
|
void hsw_enable_pc8(struct drm_i915_private *dev_priv)
|
2013-08-19 13:18:09 -03:00
|
|
|
{
|
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("Enabling package C8+\n");
|
|
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
if (HAS_PCH_LPT_LP(dev_priv)) {
|
2013-08-19 13:18:09 -03:00
|
|
|
val = I915_READ(SOUTH_DSPCLK_GATE_D);
|
|
|
|
|
val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
|
|
|
|
|
I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
lpt_disable_clkout_dp(dev_priv);
|
2013-08-19 13:18:09 -03:00
|
|
|
hsw_disable_lcpll(dev_priv, true, true);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-07 20:08:17 -03:00
|
|
|
void hsw_disable_pc8(struct drm_i915_private *dev_priv)
|
2013-08-19 13:18:09 -03:00
|
|
|
{
|
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("Disabling package C8+\n");
|
|
|
|
|
|
|
|
|
|
hsw_restore_lcpll(dev_priv);
|
2016-11-23 16:21:44 +02:00
|
|
|
lpt_init_pch_refclk(dev_priv);
|
2013-08-19 13:18:09 -03:00
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
if (HAS_PCH_LPT_LP(dev_priv)) {
|
2013-08-19 13:18:09 -03:00
|
|
|
val = I915_READ(SOUTH_DSPCLK_GATE_D);
|
|
|
|
|
val |= PCH_LP_PARTITION_LEVEL_DISABLE;
|
|
|
|
|
I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 14:55:23 +02:00
|
|
|
static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
2012-10-05 12:05:55 -03:00
|
|
|
{
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) {
|
2017-03-22 15:58:45 -03:00
|
|
|
struct intel_encoder *encoder =
|
|
|
|
|
intel_ddi_get_crtc_new_encoder(crtc_state);
|
|
|
|
|
|
|
|
|
|
if (!intel_get_shared_dpll(crtc, crtc_state, encoder)) {
|
|
|
|
|
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
|
|
|
|
|
pipe_name(crtc->pipe));
|
2016-02-05 13:29:28 +02:00
|
|
|
return -EINVAL;
|
2017-03-22 15:58:45 -03:00
|
|
|
}
|
2016-02-05 13:29:28 +02:00
|
|
|
}
|
2014-06-25 22:02:02 +03:00
|
|
|
|
2014-04-24 23:55:04 +02:00
|
|
|
return 0;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2017-06-09 15:26:03 -07:00
|
|
|
static void cannonlake_get_ddi_pll(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum port port,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
enum intel_dpll_id id;
|
|
|
|
|
u32 temp;
|
|
|
|
|
|
|
|
|
|
temp = I915_READ(DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
|
2017-08-25 16:40:04 -03:00
|
|
|
id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port);
|
2017-06-09 15:26:03 -07:00
|
|
|
|
|
|
|
|
if (WARN_ON(id < SKL_DPLL0 || id > SKL_DPLL2))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-22 09:49:11 +05:30
|
|
|
static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum port port,
|
|
|
|
|
struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
2016-03-08 17:46:18 +02:00
|
|
|
enum intel_dpll_id id;
|
|
|
|
|
|
2014-08-22 09:49:11 +05:30
|
|
|
switch (port) {
|
|
|
|
|
case PORT_A:
|
2016-03-14 19:55:34 +02:00
|
|
|
id = DPLL_ID_SKL_DPLL0;
|
2014-08-22 09:49:11 +05:30
|
|
|
break;
|
|
|
|
|
case PORT_B:
|
2016-03-14 19:55:34 +02:00
|
|
|
id = DPLL_ID_SKL_DPLL1;
|
2014-08-22 09:49:11 +05:30
|
|
|
break;
|
|
|
|
|
case PORT_C:
|
2016-03-14 19:55:34 +02:00
|
|
|
id = DPLL_ID_SKL_DPLL2;
|
2014-08-22 09:49:11 +05:30
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
DRM_ERROR("Incorrect port type\n");
|
2016-03-08 17:46:18 +02:00
|
|
|
return;
|
2014-08-22 09:49:11 +05:30
|
|
|
}
|
2016-03-08 17:46:18 +02:00
|
|
|
|
|
|
|
|
pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
|
2014-08-22 09:49:11 +05:30
|
|
|
}
|
|
|
|
|
|
2014-11-13 14:55:17 +00:00
|
|
|
static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum port port,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-11-13 14:55:17 +00:00
|
|
|
{
|
2016-03-08 17:46:18 +02:00
|
|
|
enum intel_dpll_id id;
|
2016-03-08 17:46:27 +02:00
|
|
|
u32 temp;
|
2014-11-13 14:55:17 +00:00
|
|
|
|
|
|
|
|
temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
|
2016-09-01 15:08:07 -07:00
|
|
|
id = temp >> (port * 3 + 1);
|
2014-11-13 14:55:17 +00:00
|
|
|
|
2016-09-01 15:08:07 -07:00
|
|
|
if (WARN_ON(id < SKL_DPLL0 || id > SKL_DPLL3))
|
2016-03-08 17:46:18 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
|
2014-11-13 14:55:17 +00:00
|
|
|
}
|
|
|
|
|
|
2014-07-29 18:06:18 +01:00
|
|
|
static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum port port,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-07-29 18:06:18 +01:00
|
|
|
{
|
2016-03-08 17:46:18 +02:00
|
|
|
enum intel_dpll_id id;
|
2016-09-01 15:08:07 -07:00
|
|
|
uint32_t ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
|
2016-03-08 17:46:18 +02:00
|
|
|
|
2016-09-01 15:08:07 -07:00
|
|
|
switch (ddi_pll_sel) {
|
2014-07-29 18:06:18 +01:00
|
|
|
case PORT_CLK_SEL_WRPLL1:
|
2016-03-08 17:46:18 +02:00
|
|
|
id = DPLL_ID_WRPLL1;
|
2014-07-29 18:06:18 +01:00
|
|
|
break;
|
|
|
|
|
case PORT_CLK_SEL_WRPLL2:
|
2016-03-08 17:46:18 +02:00
|
|
|
id = DPLL_ID_WRPLL2;
|
2014-07-29 18:06:18 +01:00
|
|
|
break;
|
2015-11-16 14:42:12 +01:00
|
|
|
case PORT_CLK_SEL_SPLL:
|
2016-03-08 17:46:18 +02:00
|
|
|
id = DPLL_ID_SPLL;
|
2015-12-01 23:32:07 +02:00
|
|
|
break;
|
2016-03-08 17:46:26 +02:00
|
|
|
case PORT_CLK_SEL_LCPLL_810:
|
|
|
|
|
id = DPLL_ID_LCPLL_810;
|
|
|
|
|
break;
|
|
|
|
|
case PORT_CLK_SEL_LCPLL_1350:
|
|
|
|
|
id = DPLL_ID_LCPLL_1350;
|
|
|
|
|
break;
|
|
|
|
|
case PORT_CLK_SEL_LCPLL_2700:
|
|
|
|
|
id = DPLL_ID_LCPLL_2700;
|
|
|
|
|
break;
|
2016-03-08 17:46:18 +02:00
|
|
|
default:
|
2016-09-01 15:08:07 -07:00
|
|
|
MISSING_CASE(ddi_pll_sel);
|
2016-03-08 17:46:18 +02:00
|
|
|
/* fall through */
|
|
|
|
|
case PORT_CLK_SEL_NONE:
|
|
|
|
|
return;
|
2014-07-29 18:06:18 +01:00
|
|
|
}
|
2016-03-08 17:46:18 +02:00
|
|
|
|
|
|
|
|
pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
|
2014-07-29 18:06:18 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:05:41 +02:00
|
|
|
static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *pipe_config,
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 *power_domain_mask)
|
2016-03-18 17:05:41 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-18 17:05:41 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
|
|
|
|
u32 tmp;
|
|
|
|
|
|
2016-05-12 16:18:50 +03:00
|
|
|
/*
|
|
|
|
|
* The pipe->transcoder mapping is fixed with the exception of the eDP
|
|
|
|
|
* transcoder handled below.
|
|
|
|
|
*/
|
2016-03-18 17:05:41 +02:00
|
|
|
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* XXX: Do intel_display_power_get_if_enabled before reading this (for
|
|
|
|
|
* consistency and less surprising code; it's in always on power).
|
|
|
|
|
*/
|
|
|
|
|
tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
|
|
|
|
|
if (tmp & TRANS_DDI_FUNC_ENABLE) {
|
|
|
|
|
enum pipe trans_edp_pipe;
|
|
|
|
|
switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
|
|
|
|
|
default:
|
|
|
|
|
WARN(1, "unknown pipe linked to edp transcoder\n");
|
|
|
|
|
case TRANS_DDI_EDP_INPUT_A_ONOFF:
|
|
|
|
|
case TRANS_DDI_EDP_INPUT_A_ON:
|
|
|
|
|
trans_edp_pipe = PIPE_A;
|
|
|
|
|
break;
|
|
|
|
|
case TRANS_DDI_EDP_INPUT_B_ONOFF:
|
|
|
|
|
trans_edp_pipe = PIPE_B;
|
|
|
|
|
break;
|
|
|
|
|
case TRANS_DDI_EDP_INPUT_C_ONOFF:
|
|
|
|
|
trans_edp_pipe = PIPE_C;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trans_edp_pipe == crtc->pipe)
|
|
|
|
|
pipe_config->cpu_transcoder = TRANSCODER_EDP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
|
|
|
|
return false;
|
2017-02-09 11:31:21 +02:00
|
|
|
*power_domain_mask |= BIT_ULL(power_domain);
|
2016-03-18 17:05:41 +02:00
|
|
|
|
|
|
|
|
tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
|
|
|
|
|
|
|
|
|
|
return tmp & PIPECONF_ENABLE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *pipe_config,
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 *power_domain_mask)
|
2016-03-18 17:05:42 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-18 17:05:42 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
|
|
|
|
enum port port;
|
|
|
|
|
enum transcoder cpu_transcoder;
|
|
|
|
|
u32 tmp;
|
|
|
|
|
|
|
|
|
|
for_each_port_masked(port, BIT(PORT_A) | BIT(PORT_C)) {
|
|
|
|
|
if (port == PORT_A)
|
|
|
|
|
cpu_transcoder = TRANSCODER_DSI_A;
|
|
|
|
|
else
|
|
|
|
|
cpu_transcoder = TRANSCODER_DSI_C;
|
|
|
|
|
|
|
|
|
|
power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
|
|
|
|
continue;
|
2017-02-09 11:31:21 +02:00
|
|
|
*power_domain_mask |= BIT_ULL(power_domain);
|
2016-03-18 17:05:42 +02:00
|
|
|
|
2016-03-24 12:41:40 +02:00
|
|
|
/*
|
|
|
|
|
* The PLL needs to be enabled with a valid divider
|
|
|
|
|
* configuration, otherwise accessing DSI registers will hang
|
|
|
|
|
* the machine. See BSpec North Display Engine
|
|
|
|
|
* registers/MIPI[BXT]. We can break out here early, since we
|
|
|
|
|
* need the same DSI PLL to be enabled for both DSI ports.
|
|
|
|
|
*/
|
|
|
|
|
if (!intel_dsi_pll_is_enabled(dev_priv))
|
|
|
|
|
break;
|
|
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
/* XXX: this works for video mode only */
|
|
|
|
|
tmp = I915_READ(BXT_MIPI_PORT_CTRL(port));
|
|
|
|
|
if (!(tmp & DPI_ENABLE))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
tmp = I915_READ(MIPI_CTRL(port));
|
|
|
|
|
if ((tmp & BXT_PIPE_SELECT_MASK) != BXT_PIPE_SELECT(crtc->pipe))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
pipe_config->cpu_transcoder = cpu_transcoder;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
return transcoder_is_dsi(pipe_config->cpu_transcoder);
|
2016-03-18 17:05:42 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-25 22:01:55 +03:00
|
|
|
static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2014-06-25 22:01:55 +03:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2014-07-04 11:27:39 -03:00
|
|
|
struct intel_shared_dpll *pll;
|
2014-06-25 22:01:55 +03:00
|
|
|
enum port port;
|
|
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
|
|
tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe_config->cpu_transcoder));
|
|
|
|
|
|
|
|
|
|
port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
|
|
|
|
|
|
2017-06-09 15:26:03 -07:00
|
|
|
if (IS_CANNONLAKE(dev_priv))
|
|
|
|
|
cannonlake_get_ddi_pll(dev_priv, port, pipe_config);
|
|
|
|
|
else if (IS_GEN9_BC(dev_priv))
|
2014-11-13 14:55:17 +00:00
|
|
|
skylake_get_ddi_pll(dev_priv, port, pipe_config);
|
2016-12-02 10:23:49 +02:00
|
|
|
else if (IS_GEN9_LP(dev_priv))
|
2014-08-22 09:49:11 +05:30
|
|
|
bxt_get_ddi_pll(dev_priv, port, pipe_config);
|
2014-11-13 14:55:17 +00:00
|
|
|
else
|
|
|
|
|
haswell_get_ddi_pll(dev_priv, port, pipe_config);
|
2014-06-25 22:01:57 +03:00
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
pll = pipe_config->shared_dpll;
|
|
|
|
|
if (pll) {
|
2016-03-08 17:46:21 +02:00
|
|
|
WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
|
|
|
|
|
&pipe_config->dpll_hw_state));
|
2014-07-04 11:27:39 -03:00
|
|
|
}
|
|
|
|
|
|
2014-06-25 22:01:55 +03:00
|
|
|
/*
|
|
|
|
|
* Haswell has only FDI/PCH transcoder A. It is which is connected to
|
|
|
|
|
* DDI E. So just check whether this pipe is wired to DDI E and whether
|
|
|
|
|
* the PCH transcoder is on.
|
|
|
|
|
*/
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 9 &&
|
2013-12-03 13:56:24 +00:00
|
|
|
(port == PORT_E) && I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) {
|
2014-06-25 22:01:55 +03:00
|
|
|
pipe_config->has_pch_encoder = true;
|
|
|
|
|
|
|
|
|
|
tmp = I915_READ(FDI_RX_CTL(PIPE_A));
|
|
|
|
|
pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >>
|
|
|
|
|
FDI_DP_PORT_WIDTH_SHIFT) + 1;
|
|
|
|
|
|
|
|
|
|
ironlake_get_fdi_m_n_config(crtc, pipe_config);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-28 10:42:00 +01:00
|
|
|
static bool haswell_get_pipe_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-03-28 10:42:00 +01:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2016-02-12 18:55:11 +02:00
|
|
|
enum intel_display_power_domain power_domain;
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 power_domain_mask;
|
2016-03-18 17:05:41 +02:00
|
|
|
bool active;
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2017-07-20 01:50:57 +03:00
|
|
|
intel_crtc_init_scalers(crtc, pipe_config);
|
2017-07-20 14:28:20 +03:00
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
2014-03-05 16:20:55 +02:00
|
|
|
return false;
|
2017-02-09 11:31:21 +02:00
|
|
|
power_domain_mask = BIT_ULL(power_domain);
|
2016-02-12 18:55:11 +02:00
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
pipe_config->shared_dpll = NULL;
|
2013-06-07 23:11:08 +02:00
|
|
|
|
2016-03-18 17:05:41 +02:00
|
|
|
active = hsw_get_transcoder_state(crtc, pipe_config, &power_domain_mask);
|
2013-05-22 00:50:22 +02:00
|
|
|
|
2016-12-02 10:23:49 +02:00
|
|
|
if (IS_GEN9_LP(dev_priv) &&
|
2016-06-22 21:57:07 +03:00
|
|
|
bxt_get_dsi_transcoder_state(crtc, pipe_config, &power_domain_mask)) {
|
|
|
|
|
WARN_ON(active);
|
|
|
|
|
active = true;
|
2016-03-18 17:05:42 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:05:41 +02:00
|
|
|
if (!active)
|
2016-02-12 18:55:11 +02:00
|
|
|
goto out;
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2016-06-22 21:57:07 +03:00
|
|
|
if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
|
2016-03-18 17:05:42 +02:00
|
|
|
haswell_get_ddi_port_state(crtc, pipe_config);
|
|
|
|
|
intel_get_pipe_timings(crtc, pipe_config);
|
|
|
|
|
}
|
2013-04-29 19:33:42 +02:00
|
|
|
|
2016-03-18 17:05:39 +02:00
|
|
|
intel_get_pipe_src_size(crtc, pipe_config);
|
2013-04-29 21:56:12 +02:00
|
|
|
|
2016-03-16 10:57:15 +00:00
|
|
|
pipe_config->gamma_mode =
|
|
|
|
|
I915_READ(GAMMA_MODE(crtc->pipe)) & GAMMA_MODE_MODE_MASK;
|
|
|
|
|
|
2017-09-26 14:13:46 -07:00
|
|
|
if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) {
|
2017-07-24 19:19:32 +05:30
|
|
|
u32 tmp = I915_READ(PIPEMISC(crtc->pipe));
|
|
|
|
|
bool clrspace_yuv = tmp & PIPEMISC_OUTPUT_COLORSPACE_YUV;
|
|
|
|
|
|
2017-09-26 14:13:46 -07:00
|
|
|
if (IS_GEMINILAKE(dev_priv) || INTEL_GEN(dev_priv) >= 10) {
|
2017-07-24 19:19:32 +05:30
|
|
|
bool blend_mode_420 = tmp &
|
|
|
|
|
PIPEMISC_YUV420_MODE_FULL_BLEND;
|
|
|
|
|
|
|
|
|
|
pipe_config->ycbcr420 = tmp & PIPEMISC_YUV420_ENABLE;
|
|
|
|
|
if (pipe_config->ycbcr420 != clrspace_yuv ||
|
|
|
|
|
pipe_config->ycbcr420 != blend_mode_420)
|
|
|
|
|
DRM_DEBUG_KMS("Bad 4:2:0 mode (%08x)\n", tmp);
|
|
|
|
|
} else if (clrspace_yuv) {
|
|
|
|
|
DRM_DEBUG_KMS("YCbCr 4:2:0 Unsupported\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
|
|
|
|
|
if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
|
2017-02-09 11:31:21 +02:00
|
|
|
power_domain_mask |= BIT_ULL(power_domain);
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2014-11-13 17:51:47 +00:00
|
|
|
skylake_get_pfit_config(crtc, pipe_config);
|
2015-01-21 17:19:54 -08:00
|
|
|
else
|
2015-09-02 15:19:26 -07:00
|
|
|
ironlake_get_pfit_config(crtc, pipe_config);
|
2014-11-13 17:51:47 +00:00
|
|
|
}
|
2013-03-28 10:42:01 +01:00
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (hsw_crtc_supports_ips(crtc)) {
|
|
|
|
|
if (IS_HASWELL(dev_priv))
|
|
|
|
|
pipe_config->ips_enabled = I915_READ(IPS_CTL) & IPS_ENABLE;
|
|
|
|
|
else {
|
|
|
|
|
/*
|
|
|
|
|
* We cannot readout IPS state on broadwell, set to
|
|
|
|
|
* true so we can set it to a defined state on first
|
|
|
|
|
* commit.
|
|
|
|
|
*/
|
|
|
|
|
pipe_config->ips_enabled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
if (pipe_config->cpu_transcoder != TRANSCODER_EDP &&
|
|
|
|
|
!transcoder_is_dsi(pipe_config->cpu_transcoder)) {
|
2014-09-30 10:30:22 -07:00
|
|
|
pipe_config->pixel_multiplier =
|
|
|
|
|
I915_READ(PIPE_MULT(pipe_config->cpu_transcoder)) + 1;
|
|
|
|
|
} else {
|
|
|
|
|
pipe_config->pixel_multiplier = 1;
|
|
|
|
|
}
|
2013-06-06 12:45:25 +02:00
|
|
|
|
2016-02-12 18:55:11 +02:00
|
|
|
out:
|
|
|
|
|
for_each_power_domain(power_domain, power_domain_mask)
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
|
2016-03-18 17:05:41 +02:00
|
|
|
return active;
|
2013-03-28 10:42:00 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:35 +03:00
|
|
|
static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
|
2017-03-27 21:55:34 +03:00
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
|
|
|
|
u32 base;
|
|
|
|
|
|
|
|
|
|
if (INTEL_INFO(dev_priv)->cursor_needs_physical)
|
|
|
|
|
base = obj->phys_handle->busaddr;
|
|
|
|
|
else
|
|
|
|
|
base = intel_plane_ggtt_offset(plane_state);
|
|
|
|
|
|
2017-03-27 21:55:44 +03:00
|
|
|
base += plane_state->main.offset;
|
|
|
|
|
|
2017-03-27 21:55:34 +03:00
|
|
|
/* ILK+ do this automagically */
|
|
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv) &&
|
2017-05-30 15:25:28 +10:00
|
|
|
plane_state->base.rotation & DRM_MODE_ROTATE_180)
|
2017-03-27 21:55:34 +03:00
|
|
|
base += (plane_state->base.crtc_h *
|
|
|
|
|
plane_state->base.crtc_w - 1) * fb->format->cpp[0];
|
|
|
|
|
|
|
|
|
|
return base;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:36 +03:00
|
|
|
static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
int x = plane_state->base.crtc_x;
|
|
|
|
|
int y = plane_state->base.crtc_y;
|
|
|
|
|
u32 pos = 0;
|
|
|
|
|
|
|
|
|
|
if (x < 0) {
|
|
|
|
|
pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
|
|
|
|
|
x = -x;
|
|
|
|
|
}
|
|
|
|
|
pos |= x << CURSOR_X_SHIFT;
|
|
|
|
|
|
|
|
|
|
if (y < 0) {
|
|
|
|
|
pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
|
|
|
|
|
y = -y;
|
|
|
|
|
}
|
|
|
|
|
pos |= y << CURSOR_Y_SHIFT;
|
|
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:40 +03:00
|
|
|
static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
const struct drm_mode_config *config =
|
|
|
|
|
&plane_state->base.plane->dev->mode_config;
|
|
|
|
|
int width = plane_state->base.crtc_w;
|
|
|
|
|
int height = plane_state->base.crtc_h;
|
|
|
|
|
|
|
|
|
|
return width > 0 && width <= config->cursor_width &&
|
|
|
|
|
height > 0 && height <= config->cursor_height;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
static int intel_check_cursor(struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
2017-03-27 21:55:44 +03:00
|
|
|
int src_x, src_y;
|
|
|
|
|
u32 offset;
|
2017-03-27 21:55:39 +03:00
|
|
|
int ret;
|
|
|
|
|
|
2017-11-01 22:16:19 +02:00
|
|
|
ret = drm_atomic_helper_check_plane_state(&plane_state->base,
|
|
|
|
|
&crtc_state->base,
|
|
|
|
|
&plane_state->clip,
|
|
|
|
|
DRM_PLANE_HELPER_NO_SCALING,
|
|
|
|
|
DRM_PLANE_HELPER_NO_SCALING,
|
|
|
|
|
true, true);
|
2017-03-27 21:55:39 +03:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
if (!fb)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
|
|
|
|
|
DRM_DEBUG_KMS("cursor cannot be tiled\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:44 +03:00
|
|
|
src_x = plane_state->base.src_x >> 16;
|
|
|
|
|
src_y = plane_state->base.src_y >> 16;
|
|
|
|
|
|
|
|
|
|
intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
|
|
|
|
|
offset = intel_compute_tile_offset(&src_x, &src_y, plane_state, 0);
|
|
|
|
|
|
|
|
|
|
if (src_x != 0 || src_y != 0) {
|
|
|
|
|
DRM_DEBUG_KMS("Arbitrary cursor panning not supported\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plane_state->main.offset = offset;
|
|
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 23:18:01 +02:00
|
|
|
static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
2017-03-27 21:55:41 +03:00
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
2017-03-17 23:18:01 +02:00
|
|
|
|
|
|
|
|
return CURSOR_ENABLE |
|
|
|
|
|
CURSOR_GAMMA_ENABLE |
|
|
|
|
|
CURSOR_FORMAT_ARGB |
|
2017-03-27 21:55:41 +03:00
|
|
|
CURSOR_STRIDE(fb->pitches[0]);
|
2017-03-17 23:18:01 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
int width = plane_state->base.crtc_w;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 845g/865g are only limited by the width of their cursors,
|
|
|
|
|
* the height is arbitrary up to the precision of the register.
|
|
|
|
|
*/
|
2017-03-27 21:55:40 +03:00
|
|
|
return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
|
2017-03-27 21:55:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int i845_check_cursor(struct intel_plane *plane,
|
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = intel_check_cursor(crtc_state, plane_state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
/* if we want to turn off the cursor ignore width and height */
|
2017-03-27 21:55:41 +03:00
|
|
|
if (!fb)
|
2017-03-27 21:55:39 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Check for which cursor types we support */
|
|
|
|
|
if (!i845_cursor_size_ok(plane_state)) {
|
|
|
|
|
DRM_DEBUG("Cursor dimension %dx%d not supported\n",
|
|
|
|
|
plane_state->base.crtc_w,
|
|
|
|
|
plane_state->base.crtc_h);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:41 +03:00
|
|
|
switch (fb->pitches[0]) {
|
2017-03-17 23:18:01 +02:00
|
|
|
case 256:
|
|
|
|
|
case 512:
|
|
|
|
|
case 1024:
|
|
|
|
|
case 2048:
|
|
|
|
|
break;
|
2017-03-27 21:55:41 +03:00
|
|
|
default:
|
|
|
|
|
DRM_DEBUG_KMS("Invalid cursor stride (%u)\n",
|
|
|
|
|
fb->pitches[0]);
|
|
|
|
|
return -EINVAL;
|
2017-03-17 23:18:01 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2017-03-17 23:18:01 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
static void i845_update_cursor(struct intel_plane *plane,
|
|
|
|
|
const struct intel_crtc_state *crtc_state,
|
2016-01-07 11:54:10 +01:00
|
|
|
const struct intel_plane_state *plane_state)
|
2010-08-07 11:01:38 +01:00
|
|
|
{
|
2017-03-27 21:55:35 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
2017-03-27 21:55:37 +03:00
|
|
|
u32 cntl = 0, base = 0, pos = 0, size = 0;
|
|
|
|
|
unsigned long irqflags;
|
2010-08-07 11:01:38 +01:00
|
|
|
|
2016-07-26 19:06:59 +03:00
|
|
|
if (plane_state && plane_state->base.visible) {
|
2016-01-07 11:54:10 +01:00
|
|
|
unsigned int width = plane_state->base.crtc_w;
|
|
|
|
|
unsigned int height = plane_state->base.crtc_h;
|
2014-08-13 11:57:05 +03:00
|
|
|
|
2017-03-23 21:27:09 +02:00
|
|
|
cntl = plane_state->ctl;
|
2014-08-13 11:57:05 +03:00
|
|
|
size = (height << 12) | width;
|
2010-08-07 11:01:38 +01:00
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
base = intel_cursor_base(plane_state);
|
|
|
|
|
pos = intel_cursor_position(plane_state);
|
2014-05-30 16:35:26 +03:00
|
|
|
}
|
2010-08-07 11:01:38 +01:00
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
2014-03-10 17:06:23 +05:30
|
|
|
|
2017-03-27 21:55:46 +03:00
|
|
|
/* On these chipsets we can only modify the base/size/stride
|
|
|
|
|
* whilst the cursor is disabled.
|
|
|
|
|
*/
|
|
|
|
|
if (plane->cursor.base != base ||
|
|
|
|
|
plane->cursor.size != size ||
|
|
|
|
|
plane->cursor.cntl != cntl) {
|
2017-03-09 17:44:33 +02:00
|
|
|
I915_WRITE_FW(CURCNTR(PIPE_A), 0);
|
|
|
|
|
I915_WRITE_FW(CURBASE(PIPE_A), base);
|
|
|
|
|
I915_WRITE_FW(CURSIZE, size);
|
2017-03-27 21:55:37 +03:00
|
|
|
I915_WRITE_FW(CURPOS(PIPE_A), pos);
|
2017-03-09 17:44:33 +02:00
|
|
|
I915_WRITE_FW(CURCNTR(PIPE_A), cntl);
|
2017-03-27 21:55:38 +03:00
|
|
|
|
2017-03-27 21:55:46 +03:00
|
|
|
plane->cursor.base = base;
|
|
|
|
|
plane->cursor.size = size;
|
|
|
|
|
plane->cursor.cntl = cntl;
|
|
|
|
|
} else {
|
|
|
|
|
I915_WRITE_FW(CURPOS(PIPE_A), pos);
|
2010-08-07 11:01:38 +01:00
|
|
|
}
|
2017-03-27 21:55:46 +03:00
|
|
|
|
2017-03-27 21:55:38 +03:00
|
|
|
POSTING_READ_FW(CURCNTR(PIPE_A));
|
2017-03-27 21:55:37 +03:00
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void i845_disable_cursor(struct intel_plane *plane,
|
|
|
|
|
struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
i845_update_cursor(plane, NULL, NULL);
|
2010-08-07 11:01:38 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
static bool i845_cursor_get_hw_state(struct intel_plane *plane)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
|
|
|
|
enum intel_display_power_domain power_domain;
|
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
|
|
power_domain = POWER_DOMAIN_PIPE(PIPE_A);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ret = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
|
|
|
|
|
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-17 23:18:01 +02:00
|
|
|
static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *plane_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
|
|
|
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
|
|
|
|
u32 cntl;
|
|
|
|
|
|
|
|
|
|
cntl = MCURSOR_GAMMA_ENABLE;
|
|
|
|
|
|
|
|
|
|
if (HAS_DDI(dev_priv))
|
|
|
|
|
cntl |= CURSOR_PIPE_CSC_ENABLE;
|
|
|
|
|
|
2017-03-27 21:55:32 +03:00
|
|
|
cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
|
2017-03-17 23:18:01 +02:00
|
|
|
|
|
|
|
|
switch (plane_state->base.crtc_w) {
|
|
|
|
|
case 64:
|
|
|
|
|
cntl |= CURSOR_MODE_64_ARGB_AX;
|
|
|
|
|
break;
|
|
|
|
|
case 128:
|
|
|
|
|
cntl |= CURSOR_MODE_128_ARGB_AX;
|
|
|
|
|
break;
|
|
|
|
|
case 256:
|
|
|
|
|
cntl |= CURSOR_MODE_256_ARGB_AX;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
MISSING_CASE(plane_state->base.crtc_w);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 16:50:17 -04:00
|
|
|
if (plane_state->base.rotation & DRM_MODE_ROTATE_180)
|
2017-03-17 23:18:01 +02:00
|
|
|
cntl |= CURSOR_ROTATE_180;
|
|
|
|
|
|
|
|
|
|
return cntl;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
|
2011-10-12 11:10:21 -07:00
|
|
|
{
|
2017-03-27 21:55:42 +03:00
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(plane_state->base.plane->dev);
|
2017-03-27 21:55:39 +03:00
|
|
|
int width = plane_state->base.crtc_w;
|
|
|
|
|
int height = plane_state->base.crtc_h;
|
2014-05-30 16:35:26 +03:00
|
|
|
|
2017-03-27 21:55:40 +03:00
|
|
|
if (!intel_cursor_size_ok(plane_state))
|
2017-03-27 21:55:39 +03:00
|
|
|
return false;
|
2014-10-23 07:41:34 -07:00
|
|
|
|
2017-03-27 21:55:42 +03:00
|
|
|
/* Cursor width is limited to a few power-of-two sizes */
|
|
|
|
|
switch (width) {
|
2017-03-27 21:55:39 +03:00
|
|
|
case 256:
|
|
|
|
|
case 128:
|
|
|
|
|
case 64:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
2011-10-12 11:10:21 -07:00
|
|
|
}
|
2014-05-30 16:35:26 +03:00
|
|
|
|
2017-03-27 21:55:42 +03:00
|
|
|
/*
|
|
|
|
|
* IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
|
|
|
|
|
* height from 8 lines up to the cursor width, when the
|
|
|
|
|
* cursor is not rotated. Everything else requires square
|
|
|
|
|
* cursors.
|
|
|
|
|
*/
|
|
|
|
|
if (HAS_CUR_FBC(dev_priv) &&
|
2017-05-30 15:25:28 +10:00
|
|
|
plane_state->base.rotation & DRM_MODE_ROTATE_0) {
|
2017-03-27 21:55:42 +03:00
|
|
|
if (height < 8 || height > width)
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if (height != width)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-09-12 20:53:32 +03:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
return true;
|
2011-10-12 11:10:21 -07:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
static int i9xx_check_cursor(struct intel_plane *plane,
|
|
|
|
|
struct intel_crtc_state *crtc_state,
|
|
|
|
|
struct intel_plane_state *plane_state)
|
2010-07-09 08:45:04 +01:00
|
|
|
{
|
2017-03-27 21:55:39 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
|
|
|
|
const struct drm_framebuffer *fb = plane_state->base.fb;
|
|
|
|
|
enum pipe pipe = plane->pipe;
|
|
|
|
|
int ret;
|
2010-07-09 08:45:04 +01:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
ret = intel_check_cursor(crtc_state, plane_state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2010-07-09 08:45:04 +01:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
/* if we want to turn off the cursor ignore width and height */
|
2017-03-27 21:55:41 +03:00
|
|
|
if (!fb)
|
2017-03-27 21:55:39 +03:00
|
|
|
return 0;
|
2016-01-07 11:54:10 +01:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
/* Check for which cursor types we support */
|
|
|
|
|
if (!i9xx_cursor_size_ok(plane_state)) {
|
|
|
|
|
DRM_DEBUG("Cursor dimension %dx%d not supported\n",
|
|
|
|
|
plane_state->base.crtc_w,
|
|
|
|
|
plane_state->base.crtc_h);
|
|
|
|
|
return -EINVAL;
|
2010-07-09 08:45:04 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:41 +03:00
|
|
|
if (fb->pitches[0] != plane_state->base.crtc_w * fb->format->cpp[0]) {
|
|
|
|
|
DRM_DEBUG_KMS("Invalid cursor stride (%u) (cursor width %d)\n",
|
|
|
|
|
fb->pitches[0], plane_state->base.crtc_w);
|
|
|
|
|
return -EINVAL;
|
2017-03-27 21:55:39 +03:00
|
|
|
}
|
2017-03-09 17:44:33 +02:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
/*
|
|
|
|
|
* There's something wrong with the cursor on CHV pipe C.
|
|
|
|
|
* If it straddles the left edge of the screen then
|
|
|
|
|
* moving it away from the edge or disabling it often
|
|
|
|
|
* results in a pipe underrun, and often that can lead to
|
|
|
|
|
* dead pipe (constant underrun reported, and it scans
|
|
|
|
|
* out just a solid color). To recover from that, the
|
|
|
|
|
* display power well must be turned off and on again.
|
|
|
|
|
* Refuse the put the cursor into that compromised position.
|
|
|
|
|
*/
|
|
|
|
|
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
|
|
|
|
|
plane_state->base.visible && plane_state->base.crtc_x < 0) {
|
|
|
|
|
DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
2014-04-09 13:28:53 +03:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
|
2017-03-09 17:44:33 +02:00
|
|
|
|
2017-03-27 21:55:39 +03:00
|
|
|
return 0;
|
2010-07-09 08:45:04 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
static void i9xx_update_cursor(struct intel_plane *plane,
|
|
|
|
|
const struct intel_crtc_state *crtc_state,
|
2016-01-07 11:54:10 +01:00
|
|
|
const struct intel_plane_state *plane_state)
|
2014-08-13 11:57:05 +03:00
|
|
|
{
|
2017-03-27 21:55:35 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
|
|
|
|
enum pipe pipe = plane->pipe;
|
2017-03-27 21:55:42 +03:00
|
|
|
u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
|
2017-03-27 21:55:37 +03:00
|
|
|
unsigned long irqflags;
|
2014-08-13 11:57:05 +03:00
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
if (plane_state && plane_state->base.visible) {
|
2017-03-23 21:27:09 +02:00
|
|
|
cntl = plane_state->ctl;
|
2014-08-13 11:57:05 +03:00
|
|
|
|
2017-03-27 21:55:42 +03:00
|
|
|
if (plane_state->base.crtc_h != plane_state->base.crtc_w)
|
|
|
|
|
fbc_ctl = CUR_FBC_CTL_EN | (plane_state->base.crtc_h - 1);
|
2014-08-13 11:57:05 +03:00
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
base = intel_cursor_base(plane_state);
|
|
|
|
|
pos = intel_cursor_position(plane_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
|
|
|
|
|
2017-03-27 21:55:46 +03:00
|
|
|
/*
|
|
|
|
|
* On some platforms writing CURCNTR first will also
|
|
|
|
|
* cause CURPOS to be armed by the CURBASE write.
|
|
|
|
|
* Without the CURCNTR write the CURPOS write would
|
2017-07-14 18:52:27 +03:00
|
|
|
* arm itself. Thus we always start the full update
|
|
|
|
|
* with a CURCNTR write.
|
|
|
|
|
*
|
|
|
|
|
* On other platforms CURPOS always requires the
|
|
|
|
|
* CURBASE write to arm the update. Additonally
|
|
|
|
|
* a write to any of the cursor register will cancel
|
|
|
|
|
* an already armed cursor update. Thus leaving out
|
|
|
|
|
* the CURBASE write after CURPOS could lead to a
|
|
|
|
|
* cursor that doesn't appear to move, or even change
|
|
|
|
|
* shape. Thus we always write CURBASE.
|
2017-03-27 21:55:46 +03:00
|
|
|
*
|
|
|
|
|
* CURCNTR and CUR_FBC_CTL are always
|
|
|
|
|
* armed by the CURBASE write only.
|
|
|
|
|
*/
|
|
|
|
|
if (plane->cursor.base != base ||
|
|
|
|
|
plane->cursor.size != fbc_ctl ||
|
|
|
|
|
plane->cursor.cntl != cntl) {
|
2017-03-09 17:44:33 +02:00
|
|
|
I915_WRITE_FW(CURCNTR(pipe), cntl);
|
2017-03-27 21:55:46 +03:00
|
|
|
if (HAS_CUR_FBC(dev_priv))
|
|
|
|
|
I915_WRITE_FW(CUR_FBC_CTL(pipe), fbc_ctl);
|
2017-03-27 21:55:37 +03:00
|
|
|
I915_WRITE_FW(CURPOS(pipe), pos);
|
2017-03-27 21:55:38 +03:00
|
|
|
I915_WRITE_FW(CURBASE(pipe), base);
|
|
|
|
|
|
2017-03-27 21:55:46 +03:00
|
|
|
plane->cursor.base = base;
|
|
|
|
|
plane->cursor.size = fbc_ctl;
|
|
|
|
|
plane->cursor.cntl = cntl;
|
2014-08-13 11:57:05 +03:00
|
|
|
} else {
|
2017-03-27 21:55:46 +03:00
|
|
|
I915_WRITE_FW(CURPOS(pipe), pos);
|
2017-07-14 18:52:27 +03:00
|
|
|
I915_WRITE_FW(CURBASE(pipe), base);
|
2014-08-13 11:57:05 +03:00
|
|
|
}
|
|
|
|
|
|
2017-03-09 17:44:33 +02:00
|
|
|
POSTING_READ_FW(CURBASE(pipe));
|
2014-09-12 20:53:32 +03:00
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
2011-10-12 11:10:21 -07:00
|
|
|
}
|
|
|
|
|
|
2017-03-27 21:55:37 +03:00
|
|
|
static void i9xx_disable_cursor(struct intel_plane *plane,
|
|
|
|
|
struct intel_crtc *crtc)
|
2010-07-09 08:45:04 +01:00
|
|
|
{
|
2017-03-27 21:55:37 +03:00
|
|
|
i9xx_update_cursor(plane, NULL, NULL);
|
2014-08-13 11:57:05 +03:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:08 +02:00
|
|
|
static bool i9xx_cursor_get_hw_state(struct intel_plane *plane)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
|
|
|
|
enum intel_display_power_domain power_domain;
|
|
|
|
|
enum pipe pipe = plane->pipe;
|
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Not 100% correct for planes that can move between pipes,
|
|
|
|
|
* but that's only the case for gen2-3 which don't have any
|
|
|
|
|
* display power wells.
|
|
|
|
|
*/
|
|
|
|
|
power_domain = POWER_DOMAIN_PIPE(pipe);
|
|
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ret = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
|
|
|
|
|
|
|
|
|
|
intel_display_power_put(dev_priv, power_domain);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2014-08-13 11:57:05 +03:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/* VESA 640x480x72Hz mode to set on the pipe */
|
2017-05-18 22:38:37 +03:00
|
|
|
static const struct drm_display_mode load_detect_mode = {
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
|
|
|
|
|
704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-10 18:00:39 +01:00
|
|
|
struct drm_framebuffer *
|
2017-02-15 10:59:18 +00:00
|
|
|
intel_framebuffer_create(struct drm_i915_gem_object *obj,
|
|
|
|
|
struct drm_mode_fb_cmd2 *mode_cmd)
|
2011-04-19 08:36:26 +01:00
|
|
|
{
|
|
|
|
|
struct intel_framebuffer *intel_fb;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
|
drm/i915: On fb alloc failure, unref gem object where it gets refed
Currently when allocating a framebuffer fails, the gem object gets
unrefed at the bottom of the call stack in __intel_framebuffer_create,
not where it gets refed, which is in intel_framebuffer_create_for_mode
(via i915_gem_alloc_object) and in intel_user_framebuffer_create
(via drm_gem_object_lookup).
This invites mistakes: __intel_framebuffer_create is also called from
intelfb_alloc, and as discovered by Tvrtko Ursulin, a double unref
was introduced there with a8bb6818270c ("drm/i915: Fix error path leak
in fbdev fb allocation").
As suggested by Ville Syrjälä, fix the double unref and improve code
clarity by moving the unref away from __intel_framebuffer_create to
where the gem object gets refed.
Based on Tvrtko Ursulin's original v2.
v3: On fb alloc failure, unref gem object where it gets refed,
fix double unref in separate commit (Ville Syrjälä)
v4: Lock struct_mutex on unref (Chris Wilson)
v5: Rebase on drm-intel-nightly 2015y-09m-01d-09h-06m-08s UTC,
rephrase commit message (Jani Nicula)
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina]
Fixes: a8bb6818270c ("drm/i915: Fix error path leak in fbdev fb
allocation")
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/2161c5062ef5d6458f8ae14d924a26d4d1dba317.1446892879.git.lukas@wunner.de
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-04 11:50:58 +02:00
|
|
|
if (!intel_fb)
|
2011-04-19 08:36:26 +01:00
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
2017-02-15 10:59:18 +00:00
|
|
|
ret = intel_framebuffer_init(intel_fb, obj, mode_cmd);
|
2013-10-09 21:23:51 +02:00
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
2011-04-19 08:36:26 +01:00
|
|
|
|
|
|
|
|
return &intel_fb->base;
|
drm/i915: On fb alloc failure, unref gem object where it gets refed
Currently when allocating a framebuffer fails, the gem object gets
unrefed at the bottom of the call stack in __intel_framebuffer_create,
not where it gets refed, which is in intel_framebuffer_create_for_mode
(via i915_gem_alloc_object) and in intel_user_framebuffer_create
(via drm_gem_object_lookup).
This invites mistakes: __intel_framebuffer_create is also called from
intelfb_alloc, and as discovered by Tvrtko Ursulin, a double unref
was introduced there with a8bb6818270c ("drm/i915: Fix error path leak
in fbdev fb allocation").
As suggested by Ville Syrjälä, fix the double unref and improve code
clarity by moving the unref away from __intel_framebuffer_create to
where the gem object gets refed.
Based on Tvrtko Ursulin's original v2.
v3: On fb alloc failure, unref gem object where it gets refed,
fix double unref in separate commit (Ville Syrjälä)
v4: Lock struct_mutex on unref (Chris Wilson)
v5: Rebase on drm-intel-nightly 2015y-09m-01d-09h-06m-08s UTC,
rephrase commit message (Jani Nicula)
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina]
Fixes: a8bb6818270c ("drm/i915: Fix error path leak in fbdev fb
allocation")
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/2161c5062ef5d6458f8ae14d924a26d4d1dba317.1446892879.git.lukas@wunner.de
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-04 11:50:58 +02:00
|
|
|
|
2013-10-09 21:23:51 +02:00
|
|
|
err:
|
|
|
|
|
kfree(intel_fb);
|
|
|
|
|
return ERR_PTR(ret);
|
2011-04-19 08:36:26 +01:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 10:35:45 +01:00
|
|
|
static int intel_modeset_disable_planes(struct drm_atomic_state *state,
|
|
|
|
|
struct drm_crtc *crtc)
|
2015-04-21 17:13:09 +03:00
|
|
|
{
|
2017-12-20 10:35:45 +01:00
|
|
|
struct drm_plane *plane;
|
2015-04-21 17:13:09 +03:00
|
|
|
struct drm_plane_state *plane_state;
|
2017-12-20 10:35:45 +01:00
|
|
|
int ret, i;
|
2015-04-21 17:13:09 +03:00
|
|
|
|
2017-12-20 10:35:45 +01:00
|
|
|
ret = drm_atomic_add_affected_planes(state, crtc);
|
2015-04-21 17:13:09 +03:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2017-12-20 10:35:45 +01:00
|
|
|
|
|
|
|
|
for_each_new_plane_in_state(state, plane, plane_state, i) {
|
|
|
|
|
if (plane_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
drm_atomic_set_fb_for_plane(plane_state, NULL);
|
|
|
|
|
}
|
2015-04-21 17:13:09 +03:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-06 20:55:20 +02:00
|
|
|
int intel_get_load_detect_pipe(struct drm_connector *connector,
|
2017-05-18 22:38:37 +03:00
|
|
|
const struct drm_display_mode *mode,
|
2017-04-06 20:55:20 +02:00
|
|
|
struct intel_load_detect_pipe *old,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
|
|
|
|
struct intel_crtc *intel_crtc;
|
2012-08-12 21:20:10 +02:00
|
|
|
struct intel_encoder *intel_encoder =
|
|
|
|
|
intel_attached_encoder(connector);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
struct drm_crtc *possible_crtc;
|
2010-09-09 15:14:28 +01:00
|
|
|
struct drm_encoder *encoder = &intel_encoder->base;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
struct drm_crtc *crtc = NULL;
|
|
|
|
|
struct drm_device *dev = encoder->dev;
|
2016-10-31 22:37:06 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-11-19 12:10:12 -05:00
|
|
|
struct drm_mode_config *config = &dev->mode_config;
|
2016-02-17 09:18:35 +01:00
|
|
|
struct drm_atomic_state *state = NULL, *restore_state = NULL;
|
2015-03-20 16:18:07 +02:00
|
|
|
struct drm_connector_state *connector_state;
|
2015-04-21 17:13:01 +03:00
|
|
|
struct intel_crtc_state *crtc_state;
|
2013-11-19 12:10:12 -05:00
|
|
|
int ret, i = -1;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2011-04-19 08:36:26 +01:00
|
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
|
2014-06-03 14:56:17 +03:00
|
|
|
connector->base.id, connector->name,
|
2014-06-03 14:56:21 +03:00
|
|
|
encoder->base.id, encoder->name);
|
2011-04-19 08:36:26 +01:00
|
|
|
|
2016-02-17 09:18:35 +01:00
|
|
|
old->restore_state = NULL;
|
|
|
|
|
|
2017-04-06 20:55:20 +02:00
|
|
|
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
|
drm: Split connection_mutex out of mode_config.mutex (v3)
After the split-out of crtc locks from the big mode_config.mutex
there's still two major areas it protects:
- Various connector probe states, like connector->status, EDID
properties, probed mode lists and similar information.
- The links from connector->encoder and encoder->crtc and other
modeset-relevant connector state (e.g. properties which control the
panel fitter).
The later is used by modeset operations. But they don't really care
about the former since it's allowed to e.g. enable a disconnected VGA
output or with a mode not in the probed list.
Thus far this hasn't been a problem, but for the atomic modeset
conversion Rob Clark needs to convert all modeset relevant locks into
w/w locks. This is required because the order of acquisition is
determined by how userspace supplies the atomic modeset data. This has
run into troubles in the detect path since the i915 load detect code
needs _both_ protections offered by the mode_config.mutex: It updates
probe state and it needs to change the modeset configuration to enable
the temporary load detect pipe.
The big deal here is that for the probe/detect users of this lock a
plain mutex fits best, but for atomic modesets we really want a w/w
mutex. To fix this lets split out a new connection_mutex lock for the
modeset relevant parts.
For simplicity I've decided to only add one additional lock for all
connector/encoder links and modeset configuration states. We have
piles of different modeset objects in addition to those (like bridges
or panels), so adding per-object locks would be much more effort.
Also, we're guaranteed (at least for now) to do a full modeset if we
need to acquire this lock. Which means that fine-grained locking is
fairly irrelevant compared to the amount of time the full modeset will
take.
I've done a full audit, and there's just a few things that justify
special focus:
- Locking in drm_sysfs.c is almost completely absent. We should
sprinkle mode_config.connection_mutex over this file a bit, but
since it already lacks mode_config.mutex this patch wont make the
situation any worse. This is material for a follow-up patch.
- omap has a omap_framebuffer_flush function which walks the
connector->encoder->crtc links and is called from many contexts.
Some look like they don't acquire mode_config.mutex, so this is
already racy. Again fixing this is material for a separate patch.
- The radeon hot_plug function to retrain DP links looks at
connector->dpms. Currently this happens without any locking, so is
already racy. I think radeon_hotplug_work_func should gain
mutex_lock/unlock calls for the mode_config.connection_mutex.
- Same applies to i915's intel_dp_hot_plug. But again, this is already
racy.
- i915 load_detect code needs to acquire this lock. Which means the
w/w dance due to Rob's work will be nicely contained to _just_ this
function.
I've added fixme comments everywhere where it looks suspicious but in
the sysfs code. After a quick irc discussion with Dave Airlie it
sounds like the lack of locking in there is due to sysfs cleanup fun
at module unload.
v1: original (only compile tested)
v2: missing mutex_init(), etc (from Rob Clark)
v3: i915 needs more care in the conversion:
- Protect the edp pp logic with the connection_mutex.
- Use connection_mutex in the backlight code due to
get_pipe_from_connector.
- Use drm_modeset_lock_all in suspend/resume paths.
- Update lock checks in the overlay code.
Cc: Alex Deucher <alexdeucher@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Rob Clark <robdclark@gmail.com>
2014-05-29 23:54:47 +02:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/*
|
|
|
|
|
* Algorithm gets a little messy:
|
2011-04-19 23:21:12 +01:00
|
|
|
*
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
* - if the connector already has an assigned crtc, use it (but make
|
|
|
|
|
* sure it's on first)
|
2011-04-19 23:21:12 +01:00
|
|
|
*
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
* - try to find the first unused crtc that can drive this connector,
|
|
|
|
|
* and use that if we find one
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* See if we already have a CRTC for this connector */
|
2016-02-17 09:18:35 +01:00
|
|
|
if (connector->state->crtc) {
|
|
|
|
|
crtc = connector->state->crtc;
|
2011-04-19 23:18:09 +01:00
|
|
|
|
2013-11-19 12:10:12 -05:00
|
|
|
ret = drm_modeset_lock(&crtc->mutex, ctx);
|
2014-11-11 10:12:00 +01:00
|
|
|
if (ret)
|
2015-07-13 16:30:26 +02:00
|
|
|
goto fail;
|
2011-04-19 23:18:09 +01:00
|
|
|
|
|
|
|
|
/* Make sure the crtc and connector are running */
|
2016-02-17 09:18:35 +01:00
|
|
|
goto found;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find an unused one (if possible) */
|
2014-05-13 23:32:24 +01:00
|
|
|
for_each_crtc(dev, possible_crtc) {
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
i++;
|
|
|
|
|
if (!(encoder->possible_crtcs & (1 << i)))
|
|
|
|
|
continue;
|
2016-02-17 09:18:35 +01:00
|
|
|
|
|
|
|
|
ret = drm_modeset_lock(&possible_crtc->mutex, ctx);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
if (possible_crtc->state->enable) {
|
|
|
|
|
drm_modeset_unlock(&possible_crtc->mutex);
|
2014-08-11 13:15:36 +03:00
|
|
|
continue;
|
2016-02-17 09:18:35 +01:00
|
|
|
}
|
2014-08-11 13:15:36 +03:00
|
|
|
|
|
|
|
|
crtc = possible_crtc;
|
|
|
|
|
break;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we didn't find an unused CRTC, don't use any.
|
|
|
|
|
*/
|
|
|
|
|
if (!crtc) {
|
2011-04-19 23:10:58 +01:00
|
|
|
DRM_DEBUG_KMS("no pipe available for load-detect\n");
|
2017-04-14 22:54:25 +03:00
|
|
|
ret = -ENODEV;
|
2015-07-13 16:30:26 +02:00
|
|
|
goto fail;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:18:35 +01:00
|
|
|
found:
|
|
|
|
|
intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
|
2015-03-20 16:18:03 +02:00
|
|
|
state = drm_atomic_state_alloc(dev);
|
2016-02-17 09:18:35 +01:00
|
|
|
restore_state = drm_atomic_state_alloc(dev);
|
|
|
|
|
if (!state || !restore_state) {
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2015-03-20 16:18:03 +02:00
|
|
|
|
|
|
|
|
state->acquire_ctx = ctx;
|
2016-02-17 09:18:35 +01:00
|
|
|
restore_state->acquire_ctx = ctx;
|
2015-03-20 16:18:03 +02:00
|
|
|
|
2015-03-20 16:18:07 +02:00
|
|
|
connector_state = drm_atomic_get_connector_state(state, connector);
|
|
|
|
|
if (IS_ERR(connector_state)) {
|
|
|
|
|
ret = PTR_ERR(connector_state);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:18:35 +01:00
|
|
|
ret = drm_atomic_set_crtc_for_connector(connector_state, crtc);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
2015-03-20 16:18:07 +02:00
|
|
|
|
2015-04-21 17:13:01 +03:00
|
|
|
crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
|
|
|
|
|
if (IS_ERR(crtc_state)) {
|
|
|
|
|
ret = PTR_ERR(crtc_state);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-11 10:45:15 +02:00
|
|
|
crtc_state->base.active = crtc_state->base.enable = true;
|
2015-04-21 17:13:01 +03:00
|
|
|
|
2011-04-20 07:25:26 +01:00
|
|
|
if (!mode)
|
|
|
|
|
mode = &load_detect_mode;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-12-20 10:35:45 +01:00
|
|
|
ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, mode);
|
2015-04-21 17:13:09 +03:00
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
2017-12-20 10:35:45 +01:00
|
|
|
ret = intel_modeset_disable_planes(state, crtc);
|
2016-02-17 09:18:35 +01:00
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(restore_state, connector));
|
|
|
|
|
if (!ret)
|
|
|
|
|
ret = PTR_ERR_OR_ZERO(drm_atomic_get_crtc_state(restore_state, crtc));
|
|
|
|
|
if (ret) {
|
|
|
|
|
DRM_DEBUG_KMS("Failed to create a copy of old state to restore: %i\n", ret);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2015-04-21 17:13:19 +03:00
|
|
|
|
2016-02-29 09:18:57 +01:00
|
|
|
ret = drm_atomic_commit(state);
|
|
|
|
|
if (ret) {
|
2011-04-20 07:25:26 +01:00
|
|
|
DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
|
2014-01-17 15:59:39 +02:00
|
|
|
goto fail;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
2016-02-17 09:18:35 +01:00
|
|
|
|
|
|
|
|
old->restore_state = restore_state;
|
2017-01-19 11:37:49 +00:00
|
|
|
drm_atomic_state_put(state);
|
2011-04-19 23:10:58 +01:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/* let the connector get through one full cycle before testing */
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
|
2011-04-19 23:10:58 +01:00
|
|
|
return true;
|
2014-01-17 15:59:39 +02:00
|
|
|
|
2015-07-13 16:30:26 +02:00
|
|
|
fail:
|
2016-10-19 12:37:43 +01:00
|
|
|
if (state) {
|
|
|
|
|
drm_atomic_state_put(state);
|
|
|
|
|
state = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (restore_state) {
|
|
|
|
|
drm_atomic_state_put(restore_state);
|
|
|
|
|
restore_state = NULL;
|
|
|
|
|
}
|
2015-03-20 16:18:03 +02:00
|
|
|
|
2017-04-06 20:55:20 +02:00
|
|
|
if (ret == -EDEADLK)
|
|
|
|
|
return ret;
|
2013-11-19 12:10:12 -05:00
|
|
|
|
2014-01-17 15:59:39 +02:00
|
|
|
return false;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2012-08-12 21:20:10 +02:00
|
|
|
void intel_release_load_detect_pipe(struct drm_connector *connector,
|
2015-03-20 16:18:02 +02:00
|
|
|
struct intel_load_detect_pipe *old,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2012-08-12 21:20:10 +02:00
|
|
|
struct intel_encoder *intel_encoder =
|
|
|
|
|
intel_attached_encoder(connector);
|
2010-09-09 15:14:28 +01:00
|
|
|
struct drm_encoder *encoder = &intel_encoder->base;
|
2016-02-17 09:18:35 +01:00
|
|
|
struct drm_atomic_state *state = old->restore_state;
|
2015-04-21 17:13:09 +03:00
|
|
|
int ret;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2011-04-19 08:36:26 +01:00
|
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
|
2014-06-03 14:56:17 +03:00
|
|
|
connector->base.id, connector->name,
|
2014-06-03 14:56:21 +03:00
|
|
|
encoder->base.id, encoder->name);
|
2011-04-19 08:36:26 +01:00
|
|
|
|
2016-02-17 09:18:35 +01:00
|
|
|
if (!state)
|
2011-04-21 09:32:11 +01:00
|
|
|
return;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-01-16 10:37:38 +01:00
|
|
|
ret = drm_atomic_helper_commit_duplicated_state(state, ctx);
|
2016-10-14 13:18:18 +01:00
|
|
|
if (ret)
|
2016-02-17 09:18:35 +01:00
|
|
|
DRM_DEBUG_KMS("Couldn't release load detect pipe: %i\n", ret);
|
2016-10-14 13:18:18 +01:00
|
|
|
drm_atomic_state_put(state);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2013-09-09 14:06:37 +03:00
|
|
|
static int i9xx_pll_refclk(struct drm_device *dev,
|
2015-01-15 14:55:21 +02:00
|
|
|
const struct intel_crtc_state *pipe_config)
|
2013-09-09 14:06:37 +03:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-09-09 14:06:37 +03:00
|
|
|
u32 dpll = pipe_config->dpll_hw_state.dpll;
|
|
|
|
|
|
|
|
|
|
if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
|
2013-12-09 18:54:16 +02:00
|
|
|
return dev_priv->vbt.lvds_ssc_freq;
|
2016-10-13 11:02:53 +01:00
|
|
|
else if (HAS_PCH_SPLIT(dev_priv))
|
2013-09-09 14:06:37 +03:00
|
|
|
return 120000;
|
2016-10-13 11:03:10 +01:00
|
|
|
else if (!IS_GEN2(dev_priv))
|
2013-09-09 14:06:37 +03:00
|
|
|
return 96000;
|
|
|
|
|
else
|
|
|
|
|
return 48000;
|
|
|
|
|
}
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
/* Returns the clock of the currently programmed mode of the given pipe. */
|
2013-06-27 00:39:25 +03:00
|
|
|
static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2013-06-27 00:39:25 +03:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-06-27 00:39:25 +03:00
|
|
|
int pipe = pipe_config->cpu_transcoder;
|
2013-09-13 16:18:46 +03:00
|
|
|
u32 dpll = pipe_config->dpll_hw_state.dpll;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
u32 fp;
|
2016-05-04 12:11:57 +03:00
|
|
|
struct dpll clock;
|
2015-06-22 23:35:51 +03:00
|
|
|
int port_clock;
|
2013-09-09 14:06:37 +03:00
|
|
|
int refclk = i9xx_pll_refclk(dev, pipe_config);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
|
|
|
|
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
|
2013-09-13 16:18:46 +03:00
|
|
|
fp = pipe_config->dpll_hw_state.fp0;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
else
|
2013-09-13 16:18:46 +03:00
|
|
|
fp = pipe_config->dpll_hw_state.fp1;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
|
|
|
|
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
|
2016-10-31 22:37:15 +02:00
|
|
|
if (IS_PINEVIEW(dev_priv)) {
|
2009-12-03 17:14:42 -05:00
|
|
|
clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1;
|
|
|
|
|
clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT;
|
2009-02-23 15:19:16 +08:00
|
|
|
} else {
|
|
|
|
|
clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
|
|
|
|
|
clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:03:10 +01:00
|
|
|
if (!IS_GEN2(dev_priv)) {
|
2016-10-31 22:37:15 +02:00
|
|
|
if (IS_PINEVIEW(dev_priv))
|
2009-12-03 17:14:42 -05:00
|
|
|
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
|
|
|
|
|
DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
|
2009-02-23 15:19:16 +08:00
|
|
|
else
|
|
|
|
|
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
DPLL_FPA01_P1_POST_DIV_SHIFT);
|
|
|
|
|
|
|
|
|
|
switch (dpll & DPLL_MODE_MASK) {
|
|
|
|
|
case DPLLB_MODE_DAC_SERIAL:
|
|
|
|
|
clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ?
|
|
|
|
|
5 : 10;
|
|
|
|
|
break;
|
|
|
|
|
case DPLLB_MODE_LVDS:
|
|
|
|
|
clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ?
|
|
|
|
|
7 : 14;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2009-10-09 11:39:41 +08:00
|
|
|
DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
"mode\n", (int)(dpll & DPLL_MODE_MASK));
|
2013-06-27 00:39:25 +03:00
|
|
|
return;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-31 22:37:15 +02:00
|
|
|
if (IS_PINEVIEW(dev_priv))
|
2015-06-22 23:35:51 +03:00
|
|
|
port_clock = pnv_calc_dpll_params(refclk, &clock);
|
2013-06-01 17:16:17 +02:00
|
|
|
else
|
2015-06-22 23:35:51 +03:00
|
|
|
port_clock = i9xx_calc_dpll_params(refclk, &clock);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
} else {
|
2016-10-13 11:02:58 +01:00
|
|
|
u32 lvds = IS_I830(dev_priv) ? 0 : I915_READ(LVDS);
|
2013-12-09 18:54:13 +02:00
|
|
|
bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
|
|
|
|
if (is_lvds) {
|
|
|
|
|
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
|
|
|
|
|
DPLL_FPA01_P1_POST_DIV_SHIFT);
|
2013-12-09 18:54:13 +02:00
|
|
|
|
|
|
|
|
if (lvds & LVDS_CLKB_POWER_UP)
|
|
|
|
|
clock.p2 = 7;
|
|
|
|
|
else
|
|
|
|
|
clock.p2 = 14;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
} else {
|
|
|
|
|
if (dpll & PLL_P1_DIVIDE_BY_TWO)
|
|
|
|
|
clock.p1 = 2;
|
|
|
|
|
else {
|
|
|
|
|
clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
|
|
|
|
|
DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
|
|
|
|
|
}
|
|
|
|
|
if (dpll & PLL_P2_DIVIDE_BY_4)
|
|
|
|
|
clock.p2 = 4;
|
|
|
|
|
else
|
|
|
|
|
clock.p2 = 2;
|
|
|
|
|
}
|
2013-09-09 14:06:37 +03:00
|
|
|
|
2015-06-22 23:35:51 +03:00
|
|
|
port_clock = i9xx_calc_dpll_params(refclk, &clock);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2013-09-13 16:00:08 +03:00
|
|
|
/*
|
|
|
|
|
* This value includes pixel_multiplier. We will use
|
2013-09-25 16:45:37 +01:00
|
|
|
* port_clock to compute adjusted_mode.crtc_clock in the
|
2013-09-13 16:00:08 +03:00
|
|
|
* encoder's get_config() function.
|
|
|
|
|
*/
|
2015-06-22 23:35:51 +03:00
|
|
|
pipe_config->port_clock = port_clock;
|
2013-06-27 00:39:25 +03:00
|
|
|
}
|
|
|
|
|
|
2013-09-13 15:59:11 +03:00
|
|
|
int intel_dotclock_calculate(int link_freq,
|
|
|
|
|
const struct intel_link_m_n *m_n)
|
2013-06-27 00:39:25 +03:00
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The calculation for the data clock is:
|
2013-09-06 23:28:58 +03:00
|
|
|
* pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp
|
2013-06-27 00:39:25 +03:00
|
|
|
* But we want to avoid losing precison if possible, so:
|
2013-09-06 23:28:58 +03:00
|
|
|
* pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp))
|
2013-06-27 00:39:25 +03:00
|
|
|
*
|
|
|
|
|
* and the link clock is simpler:
|
2013-09-06 23:28:58 +03:00
|
|
|
* link_clock = (m * link_clock) / n
|
2013-06-27 00:39:25 +03:00
|
|
|
*/
|
|
|
|
|
|
2013-09-13 15:59:11 +03:00
|
|
|
if (!m_n->link_n)
|
|
|
|
|
return 0;
|
2013-06-27 00:39:25 +03:00
|
|
|
|
2017-09-13 11:51:53 +01:00
|
|
|
return div_u64(mul_u32_u32(m_n->link_m, link_freq), m_n->link_n);
|
2013-09-13 15:59:11 +03:00
|
|
|
}
|
2013-06-27 00:39:25 +03:00
|
|
|
|
2013-09-13 16:00:08 +03:00
|
|
|
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-09-13 15:59:11 +03:00
|
|
|
{
|
2016-02-17 21:41:09 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2013-09-13 16:00:08 +03:00
|
|
|
/* read out port_clock from the DPLL */
|
|
|
|
|
i9xx_crtc_clock_get(crtc, pipe_config);
|
2013-06-27 00:39:25 +03:00
|
|
|
|
|
|
|
|
/*
|
2016-02-17 21:41:09 +02:00
|
|
|
* In case there is an active pipe without active ports,
|
|
|
|
|
* we may need some idea for the dotclock anyway.
|
|
|
|
|
* Calculate one based on the FDI configuration.
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
*/
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.crtc_clock =
|
2016-02-17 21:41:10 +02:00
|
|
|
intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config),
|
2013-09-13 16:00:08 +03:00
|
|
|
&pipe_config->fdi_m_n);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
/* Returns the currently programmed mode of the given encoder. */
|
|
|
|
|
struct drm_display_mode *
|
|
|
|
|
intel_encoder_current_mode(struct intel_encoder *encoder)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2017-10-09 19:19:50 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
|
|
|
|
struct intel_crtc_state *crtc_state;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
struct drm_display_mode *mode;
|
2017-10-09 19:19:50 +03:00
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
enum pipe pipe;
|
|
|
|
|
|
|
|
|
|
if (!encoder->get_hw_state(encoder, &pipe))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
|
|
|
|
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
|
|
|
|
if (!mode)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
|
|
|
|
|
if (!crtc_state) {
|
2016-01-19 15:25:17 +00:00
|
|
|
kfree(mode);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
crtc_state->base.crtc = &crtc->base;
|
2016-01-19 15:25:17 +00:00
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
if (!dev_priv->display.get_pipe_config(crtc, crtc_state)) {
|
|
|
|
|
kfree(crtc_state);
|
|
|
|
|
kfree(mode);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2016-04-01 18:37:25 +03:00
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
encoder->get_config(encoder, crtc_state);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
intel_mode_from_pipe_config(mode, crtc_state);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-10-09 19:19:50 +03:00
|
|
|
kfree(crtc_state);
|
2016-01-19 15:25:17 +00:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
return mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_crtc_destroy(struct drm_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
|
|
|
|
|
drm_crtc_cleanup(crtc);
|
|
|
|
|
kfree(intel_crtc);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
/**
|
|
|
|
|
* intel_wm_need_update - Check whether watermarks need updating
|
|
|
|
|
* @plane: drm plane
|
|
|
|
|
* @state: new plane state
|
|
|
|
|
*
|
|
|
|
|
* Check current plane state versus the new one to determine whether
|
|
|
|
|
* watermarks need to be recalculated.
|
|
|
|
|
*
|
|
|
|
|
* Returns true or false.
|
|
|
|
|
*/
|
|
|
|
|
static bool intel_wm_need_update(struct drm_plane *plane,
|
|
|
|
|
struct drm_plane_state *state)
|
|
|
|
|
{
|
|
|
|
|
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. */
|
2016-07-26 19:06:59 +03:00
|
|
|
if (new->base.visible != cur->base.visible)
|
2016-05-24 17:13:53 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (!cur->base.fb || !new->base.fb)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-11-16 13:33:16 +02:00
|
|
|
if (cur->base.fb->modifier != new->base.fb->modifier ||
|
2016-05-24 17:13:53 +02:00
|
|
|
cur->base.rotation != new->base.rotation ||
|
2016-07-26 19:06:59 +03:00
|
|
|
drm_rect_width(&new->base.src) != drm_rect_width(&cur->base.src) ||
|
|
|
|
|
drm_rect_height(&new->base.src) != drm_rect_height(&cur->base.src) ||
|
|
|
|
|
drm_rect_width(&new->base.dst) != drm_rect_width(&cur->base.dst) ||
|
|
|
|
|
drm_rect_height(&new->base.dst) != drm_rect_height(&cur->base.dst))
|
2016-05-24 17:13:53 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-23 18:22:23 +03:00
|
|
|
static bool needs_scaling(const struct intel_plane_state *state)
|
2016-05-24 17:13:53 +02:00
|
|
|
{
|
2016-07-26 19:06:59 +03:00
|
|
|
int src_w = drm_rect_width(&state->base.src) >> 16;
|
|
|
|
|
int src_h = drm_rect_height(&state->base.src) >> 16;
|
|
|
|
|
int dst_w = drm_rect_width(&state->base.dst);
|
|
|
|
|
int dst_h = drm_rect_height(&state->base.dst);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
return (src_w != dst_w || src_h != dst_h);
|
|
|
|
|
}
|
2015-09-24 15:53:12 -07:00
|
|
|
|
2017-08-23 18:22:23 +03:00
|
|
|
int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
|
|
|
|
|
struct drm_crtc_state *crtc_state,
|
|
|
|
|
const struct intel_plane_state *old_plane_state,
|
2015-06-15 12:33:44 +02:00
|
|
|
struct drm_plane_state *plane_state)
|
|
|
|
|
{
|
2015-11-19 16:07:14 +01:00
|
|
|
struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state);
|
2015-06-15 12:33:44 +02:00
|
|
|
struct drm_crtc *crtc = crtc_state->crtc;
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2017-03-02 19:14:51 +02:00
|
|
|
struct intel_plane *plane = to_intel_plane(plane_state->plane);
|
2015-06-15 12:33:44 +02:00
|
|
|
struct drm_device *dev = crtc->dev;
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-06-15 12:33:44 +02:00
|
|
|
bool mode_changed = needs_modeset(crtc_state);
|
2017-08-23 18:22:23 +03:00
|
|
|
bool was_crtc_enabled = old_crtc_state->base.active;
|
2015-06-15 12:33:44 +02:00
|
|
|
bool is_crtc_enabled = crtc_state->active;
|
|
|
|
|
bool turn_off, turn_on, visible, was_visible;
|
|
|
|
|
struct drm_framebuffer *fb = plane_state->fb;
|
2016-05-27 20:59:19 +03:00
|
|
|
int ret;
|
2015-06-15 12:33:44 +02:00
|
|
|
|
2017-03-02 19:14:51 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9 && plane->id != PLANE_CURSOR) {
|
2015-06-15 12:33:44 +02:00
|
|
|
ret = skl_update_scaler_plane(
|
|
|
|
|
to_intel_crtc_state(crtc_state),
|
|
|
|
|
to_intel_plane_state(plane_state));
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-26 19:06:59 +03:00
|
|
|
was_visible = old_plane_state->base.visible;
|
2017-01-12 10:43:45 +01:00
|
|
|
visible = plane_state->visible;
|
2015-06-15 12:33:44 +02:00
|
|
|
|
|
|
|
|
if (!was_crtc_enabled && WARN_ON(was_visible))
|
|
|
|
|
was_visible = false;
|
|
|
|
|
|
2015-12-03 14:31:07 +01:00
|
|
|
/*
|
|
|
|
|
* Visibility is calculated as if the crtc was on, but
|
|
|
|
|
* after scaler setup everything depends on it being off
|
|
|
|
|
* when the crtc isn't active.
|
2016-04-29 17:31:18 +03:00
|
|
|
*
|
|
|
|
|
* FIXME this is wrong for watermarks. Watermarks should also
|
|
|
|
|
* be computed as if the pipe would be active. Perhaps move
|
|
|
|
|
* per-plane wm computation to the .check_plane() hook, and
|
|
|
|
|
* only combine the results from all planes in the current place?
|
2015-12-03 14:31:07 +01:00
|
|
|
*/
|
2017-03-02 19:14:51 +02:00
|
|
|
if (!is_crtc_enabled) {
|
2017-01-12 10:43:45 +01:00
|
|
|
plane_state->visible = visible = false;
|
2017-03-02 19:14:51 +02:00
|
|
|
to_intel_crtc_state(crtc_state)->active_planes &= ~BIT(plane->id);
|
|
|
|
|
}
|
2015-06-15 12:33:44 +02:00
|
|
|
|
|
|
|
|
if (!was_visible && !visible)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2016-02-24 11:24:26 +01:00
|
|
|
if (fb != old_plane_state->base.fb)
|
|
|
|
|
pipe_config->fb_changed = true;
|
|
|
|
|
|
2015-06-15 12:33:44 +02:00
|
|
|
turn_off = was_visible && (!visible || mode_changed);
|
|
|
|
|
turn_on = visible && (!was_visible || mode_changed);
|
|
|
|
|
|
2016-05-27 20:59:20 +03:00
|
|
|
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] has [PLANE:%d:%s] with fb %i\n",
|
2017-03-02 19:14:51 +02:00
|
|
|
intel_crtc->base.base.id, intel_crtc->base.name,
|
|
|
|
|
plane->base.base.id, plane->base.name,
|
2016-05-27 20:59:20 +03:00
|
|
|
fb ? fb->base.id : -1);
|
2015-06-15 12:33:44 +02:00
|
|
|
|
2016-05-27 20:59:20 +03:00
|
|
|
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] visible %i -> %i, off %i, on %i, ms %i\n",
|
2017-03-02 19:14:51 +02:00
|
|
|
plane->base.base.id, plane->base.name,
|
2016-05-27 20:59:20 +03:00
|
|
|
was_visible, visible,
|
2015-06-15 12:33:44 +02:00
|
|
|
turn_off, turn_on, mode_changed);
|
|
|
|
|
|
2016-03-09 19:07:25 +02:00
|
|
|
if (turn_on) {
|
2017-04-21 21:14:29 +03:00
|
|
|
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
|
2017-03-02 19:15:01 +02:00
|
|
|
pipe_config->update_wm_pre = true;
|
2016-03-09 19:07:25 +02:00
|
|
|
|
|
|
|
|
/* must disable cxsr around plane enable/disable */
|
2017-03-02 19:14:51 +02:00
|
|
|
if (plane->id != PLANE_CURSOR)
|
2016-03-09 19:07:25 +02:00
|
|
|
pipe_config->disable_cxsr = true;
|
|
|
|
|
} else if (turn_off) {
|
2017-04-21 21:14:29 +03:00
|
|
|
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
|
2017-03-02 19:15:01 +02:00
|
|
|
pipe_config->update_wm_post = true;
|
2015-12-03 13:49:13 +01:00
|
|
|
|
2015-06-24 22:00:07 +03:00
|
|
|
/* must disable cxsr around plane enable/disable */
|
2017-03-02 19:14:51 +02:00
|
|
|
if (plane->id != PLANE_CURSOR)
|
2015-11-19 16:07:14 +01:00
|
|
|
pipe_config->disable_cxsr = true;
|
2017-03-02 19:14:51 +02:00
|
|
|
} else if (intel_wm_need_update(&plane->base, plane_state)) {
|
2017-04-21 21:14:29 +03:00
|
|
|
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) {
|
2017-03-02 19:15:01 +02:00
|
|
|
/* FIXME bollocks */
|
|
|
|
|
pipe_config->update_wm_pre = true;
|
|
|
|
|
pipe_config->update_wm_post = true;
|
|
|
|
|
}
|
2015-06-24 22:00:07 +03:00
|
|
|
}
|
2015-06-15 12:33:44 +02:00
|
|
|
|
2015-08-24 16:38:23 -07:00
|
|
|
if (visible || was_visible)
|
2017-03-02 19:14:51 +02:00
|
|
|
pipe_config->fb_bits |= plane->frontbuffer_bit;
|
2015-06-24 21:59:34 +03:00
|
|
|
|
2016-03-09 10:35:45 +01:00
|
|
|
/*
|
|
|
|
|
* WaCxSRDisabledForSpriteScaling:ivb
|
|
|
|
|
*
|
|
|
|
|
* cstate->update_wm was already set above, so this flag will
|
|
|
|
|
* take effect when we commit and program watermarks.
|
|
|
|
|
*/
|
2017-03-02 19:14:51 +02:00
|
|
|
if (plane->id == PLANE_SPRITE0 && IS_IVYBRIDGE(dev_priv) &&
|
2016-03-09 10:35:45 +01:00
|
|
|
needs_scaling(to_intel_plane_state(plane_state)) &&
|
|
|
|
|
!needs_scaling(old_plane_state))
|
|
|
|
|
pipe_config->disable_lp_wm = true;
|
2015-09-24 15:53:12 -07:00
|
|
|
|
2015-06-15 12:33:44 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 12:33:40 +02:00
|
|
|
static bool encoders_cloneable(const struct intel_encoder *a,
|
|
|
|
|
const struct intel_encoder *b)
|
|
|
|
|
{
|
|
|
|
|
/* masks could be asymmetric, so check both ways */
|
|
|
|
|
return a == b || (a->cloneable & (1 << b->type) &&
|
|
|
|
|
b->cloneable & (1 << a->type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool check_single_encoder_cloning(struct drm_atomic_state *state,
|
|
|
|
|
struct intel_crtc *crtc,
|
|
|
|
|
struct intel_encoder *encoder)
|
|
|
|
|
{
|
|
|
|
|
struct intel_encoder *source_encoder;
|
|
|
|
|
struct drm_connector *connector;
|
|
|
|
|
struct drm_connector_state *connector_state;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
2015-06-15 12:33:40 +02:00
|
|
|
if (connector_state->crtc != &crtc->base)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
source_encoder =
|
|
|
|
|
to_intel_encoder(connector_state->best_encoder);
|
|
|
|
|
if (!encoders_cloneable(encoder, source_encoder))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_crtc_atomic_check(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *crtc_state)
|
|
|
|
|
{
|
2015-06-15 12:33:41 +02:00
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-06-15 12:33:40 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2015-06-15 12:33:41 +02:00
|
|
|
struct intel_crtc_state *pipe_config =
|
|
|
|
|
to_intel_crtc_state(crtc_state);
|
2015-06-15 12:33:40 +02:00
|
|
|
struct drm_atomic_state *state = crtc_state->state;
|
2015-08-05 12:37:05 +02:00
|
|
|
int ret;
|
2015-06-15 12:33:40 +02:00
|
|
|
bool mode_changed = needs_modeset(crtc_state);
|
|
|
|
|
|
2015-06-24 22:00:07 +03:00
|
|
|
if (mode_changed && !crtc_state->active)
|
2016-03-09 19:07:25 +02:00
|
|
|
pipe_config->update_wm_post = true;
|
2015-06-15 12:33:53 +02:00
|
|
|
|
2015-06-15 12:33:42 +02:00
|
|
|
if (mode_changed && crtc_state->enable &&
|
|
|
|
|
dev_priv->display.crtc_compute_clock &&
|
2016-03-08 17:46:18 +02:00
|
|
|
!WARN_ON(pipe_config->shared_dpll)) {
|
2015-06-15 12:33:42 +02:00
|
|
|
ret = dev_priv->display.crtc_compute_clock(intel_crtc,
|
|
|
|
|
pipe_config);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-16 10:57:16 +00:00
|
|
|
if (crtc_state->color_mgmt_changed) {
|
|
|
|
|
ret = intel_color_check(crtc, crtc_state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2016-05-25 14:30:41 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Changing color management on Intel hardware is
|
|
|
|
|
* handled as part of planes update.
|
|
|
|
|
*/
|
|
|
|
|
crtc_state->planes_changed = true;
|
2016-03-16 10:57:16 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-13 16:30:15 +02:00
|
|
|
ret = 0;
|
2015-09-24 15:53:16 -07:00
|
|
|
if (dev_priv->display.compute_pipe_wm) {
|
2016-03-01 11:07:22 +01:00
|
|
|
ret = dev_priv->display.compute_pipe_wm(pipe_config);
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
if (ret) {
|
|
|
|
|
DRM_DEBUG_KMS("Target pipe watermarks are invalid\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dev_priv->display.compute_intermediate_wm &&
|
|
|
|
|
!to_intel_atomic_state(state)->skip_intermediate_wm) {
|
|
|
|
|
if (WARN_ON(!dev_priv->display.compute_pipe_wm))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Calculate 'intermediate' watermarks that satisfy both the
|
|
|
|
|
* old state and the new state. We can program these
|
|
|
|
|
* immediately.
|
|
|
|
|
*/
|
2016-11-16 12:32:42 +00:00
|
|
|
ret = dev_priv->display.compute_intermediate_wm(dev,
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
intel_crtc,
|
|
|
|
|
pipe_config);
|
|
|
|
|
if (ret) {
|
|
|
|
|
DRM_DEBUG_KMS("No valid intermediate pipe watermarks are possible\n");
|
2015-09-24 15:53:16 -07:00
|
|
|
return ret;
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
}
|
2016-05-13 10:10:42 -07:00
|
|
|
} else if (dev_priv->display.compute_intermediate_wm) {
|
|
|
|
|
if (HAS_PCH_SPLIT(dev_priv) && INTEL_GEN(dev_priv) < 9)
|
|
|
|
|
pipe_config->wm.ilk.intermediate = pipe_config->wm.ilk.optimal;
|
2015-09-24 15:53:16 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2015-07-13 16:30:15 +02:00
|
|
|
if (mode_changed)
|
|
|
|
|
ret = skl_update_scaler_crtc(pipe_config);
|
|
|
|
|
|
2017-05-26 20:45:46 +05:30
|
|
|
if (!ret)
|
|
|
|
|
ret = skl_check_pipe_max_pixel_rate(intel_crtc,
|
|
|
|
|
pipe_config);
|
2015-07-13 16:30:15 +02:00
|
|
|
if (!ret)
|
2017-02-23 09:15:59 +02:00
|
|
|
ret = intel_atomic_setup_scalers(dev_priv, intel_crtc,
|
2015-07-13 16:30:15 +02:00
|
|
|
pipe_config);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 19:39:01 +01:00
|
|
|
if (HAS_IPS(dev_priv))
|
|
|
|
|
pipe_config->ips_enabled = hsw_compute_ips_config(pipe_config);
|
|
|
|
|
|
2015-07-13 16:30:15 +02:00
|
|
|
return ret;
|
2015-06-15 12:33:40 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-13 11:26:56 +03:00
|
|
|
static const struct drm_crtc_helper_funcs intel_helper_funcs = {
|
2016-05-24 17:13:53 +02:00
|
|
|
.atomic_begin = intel_begin_crtc_commit,
|
|
|
|
|
.atomic_flush = intel_finish_crtc_commit,
|
2015-06-15 12:33:40 +02:00
|
|
|
.atomic_check = intel_crtc_atomic_check,
|
2011-04-12 18:06:51 +01:00
|
|
|
};
|
|
|
|
|
|
2015-03-20 16:18:05 +02:00
|
|
|
static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct intel_connector *connector;
|
2017-03-01 10:52:25 +01:00
|
|
|
struct drm_connector_list_iter conn_iter;
|
2015-03-20 16:18:05 +02:00
|
|
|
|
2017-03-01 10:52:25 +01:00
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
|
|
|
for_each_intel_connector_iter(connector, &conn_iter) {
|
2016-05-06 15:39:03 +02:00
|
|
|
if (connector->base.state->crtc)
|
|
|
|
|
drm_connector_unreference(&connector->base);
|
|
|
|
|
|
2015-03-20 16:18:05 +02:00
|
|
|
if (connector->base.encoder) {
|
|
|
|
|
connector->base.state->best_encoder =
|
|
|
|
|
connector->base.encoder;
|
|
|
|
|
connector->base.state->crtc =
|
|
|
|
|
connector->base.encoder->crtc;
|
2016-05-06 15:39:03 +02:00
|
|
|
|
|
|
|
|
drm_connector_reference(&connector->base);
|
2015-03-20 16:18:05 +02:00
|
|
|
} else {
|
|
|
|
|
connector->base.state->best_encoder = NULL;
|
|
|
|
|
connector->base.state->crtc = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-01 10:52:25 +01:00
|
|
|
drm_connector_list_iter_end(&conn_iter);
|
2015-03-20 16:18:05 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-02 13:26:23 +02:00
|
|
|
static void
|
2014-05-18 02:24:50 +02:00
|
|
|
connected_sink_compute_bpp(struct intel_connector *connector,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2013-06-02 13:26:23 +02:00
|
|
|
{
|
2016-09-28 16:51:42 +03:00
|
|
|
const struct drm_display_info *info = &connector->base.display_info;
|
2013-06-02 13:26:23 +02:00
|
|
|
int bpp = pipe_config->pipe_bpp;
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
|
2016-09-28 16:51:42 +03:00
|
|
|
connector->base.base.id,
|
|
|
|
|
connector->base.name);
|
2013-06-02 13:26:23 +02:00
|
|
|
|
|
|
|
|
/* Don't use an invalid EDID bpc value */
|
2016-09-28 16:51:42 +03:00
|
|
|
if (info->bpc != 0 && info->bpc * 3 < bpp) {
|
2013-06-02 13:26:23 +02:00
|
|
|
DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
|
2016-09-28 16:51:42 +03:00
|
|
|
bpp, info->bpc * 3);
|
|
|
|
|
pipe_config->pipe_bpp = info->bpc * 3;
|
2013-06-02 13:26:23 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-06 12:05:45 +02:00
|
|
|
/* Clamp bpp to 8 on screens without EDID 1.4 */
|
2016-09-28 16:51:42 +03:00
|
|
|
if (info->bpc == 0 && bpp > 24) {
|
2016-07-06 12:05:45 +02:00
|
|
|
DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
|
|
|
|
|
bpp);
|
|
|
|
|
pipe_config->pipe_bpp = 24;
|
2013-06-02 13:26:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
static int
|
2013-06-02 13:26:23 +02:00
|
|
|
compute_baseline_pipe_bpp(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
{
|
2016-10-13 11:03:06 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2015-03-20 16:18:09 +02:00
|
|
|
struct drm_atomic_state *state;
|
2015-04-21 17:12:59 +03:00
|
|
|
struct drm_connector *connector;
|
|
|
|
|
struct drm_connector_state *connector_state;
|
2015-03-20 16:18:09 +02:00
|
|
|
int bpp, i;
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
|
2016-10-13 11:03:06 +01:00
|
|
|
if ((IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
|
|
|
|
|
IS_CHERRYVIEW(dev_priv)))
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
bpp = 10*3;
|
2016-10-13 11:03:06 +01:00
|
|
|
else if (INTEL_GEN(dev_priv) >= 5)
|
2015-04-10 16:22:37 +02:00
|
|
|
bpp = 12*3;
|
|
|
|
|
else
|
|
|
|
|
bpp = 8*3;
|
|
|
|
|
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
|
|
|
|
|
pipe_config->pipe_bpp = bpp;
|
|
|
|
|
|
2015-03-20 16:18:09 +02:00
|
|
|
state = pipe_config->base.state;
|
|
|
|
|
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
/* Clamp display bpp to EDID value */
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
2015-04-21 17:12:59 +03:00
|
|
|
if (connector_state->crtc != &crtc->base)
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
continue;
|
|
|
|
|
|
2015-04-21 17:12:59 +03:00
|
|
|
connected_sink_compute_bpp(to_intel_connector(connector),
|
|
|
|
|
pipe_config);
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bpp;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-19 14:53:58 +02:00
|
|
|
static void intel_dump_crtc_timings(const struct drm_display_mode *mode)
|
|
|
|
|
{
|
|
|
|
|
DRM_DEBUG_KMS("crtc timings: %d %d %d %d %d %d %d %d %d, "
|
|
|
|
|
"type: 0x%x flags: 0x%x\n",
|
2013-09-25 16:45:36 +01:00
|
|
|
mode->crtc_clock,
|
2013-09-19 14:53:58 +02:00
|
|
|
mode->crtc_hdisplay, mode->crtc_hsync_start,
|
|
|
|
|
mode->crtc_hsync_end, mode->crtc_htotal,
|
|
|
|
|
mode->crtc_vdisplay, mode->crtc_vsync_start,
|
|
|
|
|
mode->crtc_vsync_end, mode->crtc_vtotal, mode->type, mode->flags);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-17 12:30:08 +00:00
|
|
|
static inline void
|
|
|
|
|
intel_dump_m_n_config(struct intel_crtc_state *pipe_config, char *id,
|
2016-11-17 12:30:09 +00:00
|
|
|
unsigned int lane_count, struct intel_link_m_n *m_n)
|
2016-11-17 12:30:08 +00:00
|
|
|
{
|
2016-11-17 12:30:09 +00:00
|
|
|
DRM_DEBUG_KMS("%s: lanes: %i; gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
|
|
|
|
|
id, lane_count,
|
2016-11-17 12:30:08 +00:00
|
|
|
m_n->gmch_m, m_n->gmch_n,
|
|
|
|
|
m_n->link_m, m_n->link_n, m_n->tu);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-10 15:11:59 +03:00
|
|
|
#define OUTPUT_TYPE(x) [INTEL_OUTPUT_ ## x] = #x
|
|
|
|
|
|
|
|
|
|
static const char * const output_type_str[] = {
|
|
|
|
|
OUTPUT_TYPE(UNUSED),
|
|
|
|
|
OUTPUT_TYPE(ANALOG),
|
|
|
|
|
OUTPUT_TYPE(DVO),
|
|
|
|
|
OUTPUT_TYPE(SDVO),
|
|
|
|
|
OUTPUT_TYPE(LVDS),
|
|
|
|
|
OUTPUT_TYPE(TVOUT),
|
|
|
|
|
OUTPUT_TYPE(HDMI),
|
|
|
|
|
OUTPUT_TYPE(DP),
|
|
|
|
|
OUTPUT_TYPE(EDP),
|
|
|
|
|
OUTPUT_TYPE(DSI),
|
2017-10-27 22:31:24 +03:00
|
|
|
OUTPUT_TYPE(DDI),
|
2017-10-10 15:11:59 +03:00
|
|
|
OUTPUT_TYPE(DP_MST),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#undef OUTPUT_TYPE
|
|
|
|
|
|
|
|
|
|
static void snprintf_output_types(char *buf, size_t len,
|
|
|
|
|
unsigned int output_types)
|
|
|
|
|
{
|
|
|
|
|
char *str = buf;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
str[0] = '\0';
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(output_type_str); i++) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
if ((output_types & BIT(i)) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
r = snprintf(str, len, "%s%s",
|
|
|
|
|
str != buf ? "," : "", output_type_str[i]);
|
|
|
|
|
if (r >= len)
|
|
|
|
|
break;
|
|
|
|
|
str += r;
|
|
|
|
|
len -= r;
|
|
|
|
|
|
|
|
|
|
output_types &= ~BIT(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WARN_ON_ONCE(output_types != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-28 12:05:54 +02:00
|
|
|
static void intel_dump_pipe_config(struct intel_crtc *crtc,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *pipe_config,
|
2013-05-28 12:05:54 +02:00
|
|
|
const char *context)
|
|
|
|
|
{
|
2015-04-07 15:28:40 -07:00
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-10-13 11:02:52 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-04-07 15:28:40 -07:00
|
|
|
struct drm_plane *plane;
|
|
|
|
|
struct intel_plane *intel_plane;
|
|
|
|
|
struct intel_plane_state *state;
|
|
|
|
|
struct drm_framebuffer *fb;
|
2017-10-10 15:11:59 +03:00
|
|
|
char buf[64];
|
2015-04-07 15:28:40 -07:00
|
|
|
|
2016-11-17 12:30:10 +00:00
|
|
|
DRM_DEBUG_KMS("[CRTC:%d:%s]%s\n",
|
|
|
|
|
crtc->base.base.id, crtc->base.name, context);
|
2013-05-28 12:05:54 +02:00
|
|
|
|
2017-10-10 15:11:59 +03:00
|
|
|
snprintf_output_types(buf, sizeof(buf), pipe_config->output_types);
|
|
|
|
|
DRM_DEBUG_KMS("output_types: %s (0x%x)\n",
|
|
|
|
|
buf, pipe_config->output_types);
|
|
|
|
|
|
2016-11-17 12:30:11 +00:00
|
|
|
DRM_DEBUG_KMS("cpu_transcoder: %s, pipe bpp: %i, dithering: %i\n",
|
|
|
|
|
transcoder_name(pipe_config->cpu_transcoder),
|
2013-05-28 12:05:54 +02:00
|
|
|
pipe_config->pipe_bpp, pipe_config->dither);
|
2016-11-17 12:30:09 +00:00
|
|
|
|
|
|
|
|
if (pipe_config->has_pch_encoder)
|
|
|
|
|
intel_dump_m_n_config(pipe_config, "fdi",
|
|
|
|
|
pipe_config->fdi_lanes,
|
|
|
|
|
&pipe_config->fdi_m_n);
|
2016-11-17 12:30:08 +00:00
|
|
|
|
2017-07-24 19:19:32 +05:30
|
|
|
if (pipe_config->ycbcr420)
|
|
|
|
|
DRM_DEBUG_KMS("YCbCr 4:2:0 output enabled\n");
|
|
|
|
|
|
2016-11-17 12:30:08 +00:00
|
|
|
if (intel_crtc_has_dp_encoder(pipe_config)) {
|
2016-11-17 12:30:09 +00:00
|
|
|
intel_dump_m_n_config(pipe_config, "dp m_n",
|
|
|
|
|
pipe_config->lane_count, &pipe_config->dp_m_n);
|
2016-11-17 15:44:09 +00:00
|
|
|
if (pipe_config->has_drrs)
|
|
|
|
|
intel_dump_m_n_config(pipe_config, "dp m2_n2",
|
|
|
|
|
pipe_config->lane_count,
|
|
|
|
|
&pipe_config->dp_m2_n2);
|
2016-11-17 12:30:08 +00:00
|
|
|
}
|
2014-08-05 07:51:23 -07:00
|
|
|
|
2014-11-20 16:10:28 +01:00
|
|
|
DRM_DEBUG_KMS("audio: %i, infoframes: %i\n",
|
2016-11-17 12:30:11 +00:00
|
|
|
pipe_config->has_audio, pipe_config->has_infoframe);
|
2014-11-20 16:10:28 +01:00
|
|
|
|
2013-05-28 12:05:54 +02:00
|
|
|
DRM_DEBUG_KMS("requested mode:\n");
|
2015-01-15 14:55:22 +02:00
|
|
|
drm_mode_debug_printmodeline(&pipe_config->base.mode);
|
2013-05-28 12:05:54 +02:00
|
|
|
DRM_DEBUG_KMS("adjusted mode:\n");
|
2015-01-15 14:55:22 +02:00
|
|
|
drm_mode_debug_printmodeline(&pipe_config->base.adjusted_mode);
|
|
|
|
|
intel_dump_crtc_timings(&pipe_config->base.adjusted_mode);
|
2017-01-26 21:50:31 +02:00
|
|
|
DRM_DEBUG_KMS("port clock: %d, pipe src size: %dx%d, pixel rate %d\n",
|
2016-11-17 12:30:11 +00:00
|
|
|
pipe_config->port_clock,
|
2017-01-26 21:50:31 +02:00
|
|
|
pipe_config->pipe_src_w, pipe_config->pipe_src_h,
|
|
|
|
|
pipe_config->pixel_rate);
|
2016-11-17 12:30:12 +00:00
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
|
|
|
|
DRM_DEBUG_KMS("num_scalers: %d, scaler_users: 0x%x, scaler_id: %d\n",
|
|
|
|
|
crtc->num_scalers,
|
|
|
|
|
pipe_config->scaler_state.scaler_users,
|
|
|
|
|
pipe_config->scaler_state.scaler_id);
|
2016-11-17 12:30:13 +00:00
|
|
|
|
|
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv))
|
|
|
|
|
DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
|
|
|
|
|
pipe_config->gmch_pfit.control,
|
|
|
|
|
pipe_config->gmch_pfit.pgm_ratios,
|
|
|
|
|
pipe_config->gmch_pfit.lvds_border_bits);
|
|
|
|
|
else
|
|
|
|
|
DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x, %s\n",
|
|
|
|
|
pipe_config->pch_pfit.pos,
|
|
|
|
|
pipe_config->pch_pfit.size,
|
2016-11-17 12:30:14 +00:00
|
|
|
enableddisabled(pipe_config->pch_pfit.enabled));
|
2016-11-17 12:30:13 +00:00
|
|
|
|
2016-11-17 12:30:11 +00:00
|
|
|
DRM_DEBUG_KMS("ips: %i, double wide: %i\n",
|
|
|
|
|
pipe_config->ips_enabled, pipe_config->double_wide);
|
2015-04-07 15:28:40 -07:00
|
|
|
|
2016-12-29 17:22:12 +02:00
|
|
|
intel_dpll_dump_hw_state(dev_priv, &pipe_config->dpll_hw_state);
|
2015-05-14 13:38:31 +01:00
|
|
|
|
2015-04-07 15:28:40 -07:00
|
|
|
DRM_DEBUG_KMS("planes on this crtc\n");
|
|
|
|
|
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
|
2016-11-12 01:12:56 +00:00
|
|
|
struct drm_format_name_buf format_name;
|
2015-04-07 15:28:40 -07:00
|
|
|
intel_plane = to_intel_plane(plane);
|
|
|
|
|
if (intel_plane->pipe != crtc->pipe)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
state = to_intel_plane_state(plane->state);
|
|
|
|
|
fb = state->base.fb;
|
|
|
|
|
if (!fb) {
|
2016-05-27 20:59:25 +03:00
|
|
|
DRM_DEBUG_KMS("[PLANE:%d:%s] disabled, scaler_id = %d\n",
|
|
|
|
|
plane->base.id, plane->name, state->scaler_id);
|
2015-04-07 15:28:40 -07:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-17 12:30:12 +00:00
|
|
|
DRM_DEBUG_KMS("[PLANE:%d:%s] FB:%d, fb = %ux%u format = %s\n",
|
|
|
|
|
plane->base.id, plane->name,
|
2016-11-12 01:12:56 +00:00
|
|
|
fb->base.id, fb->width, fb->height,
|
2016-12-14 23:32:55 +02:00
|
|
|
drm_get_format_name(fb->format->format, &format_name));
|
2016-11-17 12:30:12 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
|
|
|
|
DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n",
|
|
|
|
|
state->scaler_id,
|
|
|
|
|
state->base.src.x1 >> 16,
|
|
|
|
|
state->base.src.y1 >> 16,
|
|
|
|
|
drm_rect_width(&state->base.src) >> 16,
|
|
|
|
|
drm_rect_height(&state->base.src) >> 16,
|
|
|
|
|
state->base.dst.x1, state->base.dst.y1,
|
|
|
|
|
drm_rect_width(&state->base.dst),
|
|
|
|
|
drm_rect_height(&state->base.dst));
|
2015-04-07 15:28:40 -07:00
|
|
|
}
|
2013-05-28 12:05:54 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-02 14:47:59 +03:00
|
|
|
static bool check_digital_port_conflicts(struct drm_atomic_state *state)
|
2014-12-02 14:10:46 +02:00
|
|
|
{
|
2015-04-02 14:47:59 +03:00
|
|
|
struct drm_device *dev = state->dev;
|
2015-04-21 17:12:59 +03:00
|
|
|
struct drm_connector *connector;
|
2017-05-11 16:10:44 -03:00
|
|
|
struct drm_connector_list_iter conn_iter;
|
2014-12-02 14:10:46 +02:00
|
|
|
unsigned int used_ports = 0;
|
2016-07-28 17:50:40 +03:00
|
|
|
unsigned int used_mst_ports = 0;
|
2014-12-02 14:10:46 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk the connector list instead of the encoder
|
|
|
|
|
* list to detect the problem on ddi platforms
|
|
|
|
|
* where there's just one encoder per digital port.
|
|
|
|
|
*/
|
2017-05-11 16:10:44 -03:00
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
|
|
|
drm_for_each_connector_iter(connector, &conn_iter) {
|
2015-12-10 18:22:31 +02:00
|
|
|
struct drm_connector_state *connector_state;
|
|
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
|
|
|
|
|
connector_state = drm_atomic_get_existing_connector_state(state, connector);
|
|
|
|
|
if (!connector_state)
|
|
|
|
|
connector_state = connector->state;
|
|
|
|
|
|
2015-04-02 14:47:59 +03:00
|
|
|
if (!connector_state->best_encoder)
|
2014-12-02 14:10:46 +02:00
|
|
|
continue;
|
|
|
|
|
|
2015-04-02 14:47:59 +03:00
|
|
|
encoder = to_intel_encoder(connector_state->best_encoder);
|
|
|
|
|
|
|
|
|
|
WARN_ON(!connector_state->crtc);
|
2014-12-02 14:10:46 +02:00
|
|
|
|
|
|
|
|
switch (encoder->type) {
|
|
|
|
|
unsigned int port_mask;
|
2017-10-27 22:31:24 +03:00
|
|
|
case INTEL_OUTPUT_DDI:
|
2016-10-13 11:02:52 +01:00
|
|
|
if (WARN_ON(!HAS_DDI(to_i915(dev))))
|
2014-12-02 14:10:46 +02:00
|
|
|
break;
|
2016-06-22 21:57:06 +03:00
|
|
|
case INTEL_OUTPUT_DP:
|
2014-12-02 14:10:46 +02:00
|
|
|
case INTEL_OUTPUT_HDMI:
|
|
|
|
|
case INTEL_OUTPUT_EDP:
|
2017-11-09 17:24:34 +02:00
|
|
|
port_mask = 1 << encoder->port;
|
2014-12-02 14:10:46 +02:00
|
|
|
|
|
|
|
|
/* the same port mustn't appear more than once */
|
|
|
|
|
if (used_ports & port_mask)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
used_ports |= port_mask;
|
2016-07-28 17:50:40 +03:00
|
|
|
break;
|
|
|
|
|
case INTEL_OUTPUT_DP_MST:
|
|
|
|
|
used_mst_ports |=
|
2017-11-09 17:24:34 +02:00
|
|
|
1 << encoder->port;
|
2016-07-28 17:50:40 +03:00
|
|
|
break;
|
2014-12-02 14:10:46 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-11 16:10:44 -03:00
|
|
|
drm_connector_list_iter_end(&conn_iter);
|
2014-12-02 14:10:46 +02:00
|
|
|
|
2016-07-28 17:50:40 +03:00
|
|
|
/* can't mix MST and SST/HDMI on the same port */
|
|
|
|
|
if (used_ports & used_mst_ports)
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-12-02 14:10:46 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:18:03 +02:00
|
|
|
static void
|
|
|
|
|
clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
2017-03-02 19:14:57 +02:00
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
to_i915(crtc_state->base.crtc->dev);
|
2015-04-07 15:28:41 -07:00
|
|
|
struct intel_crtc_scaler_state scaler_state;
|
2015-04-21 17:13:21 +03:00
|
|
|
struct intel_dpll_hw_state dpll_hw_state;
|
2016-03-08 17:46:18 +02:00
|
|
|
struct intel_shared_dpll *shared_dpll;
|
2017-03-02 19:14:57 +02:00
|
|
|
struct intel_crtc_wm_state wm_state;
|
2017-08-17 17:55:09 +03:00
|
|
|
bool force_thru, ips_force_disable;
|
2015-03-20 16:18:03 +02:00
|
|
|
|
2015-05-20 09:03:27 +03:00
|
|
|
/* FIXME: before the switch to atomic started, a new pipe_config was
|
|
|
|
|
* kzalloc'd. Code that depends on any field being zero should be
|
|
|
|
|
* fixed, so that the crtc_state can be safely duplicated. For now,
|
|
|
|
|
* only fields that are know to not cause problems are preserved. */
|
|
|
|
|
|
2015-04-07 15:28:41 -07:00
|
|
|
scaler_state = crtc_state->scaler_state;
|
2015-04-21 17:13:21 +03:00
|
|
|
shared_dpll = crtc_state->shared_dpll;
|
|
|
|
|
dpll_hw_state = crtc_state->dpll_hw_state;
|
2015-08-05 12:36:59 +02:00
|
|
|
force_thru = crtc_state->pch_pfit.force_thru;
|
2017-08-17 17:55:09 +03:00
|
|
|
ips_force_disable = crtc_state->ips_force_disable;
|
2017-04-21 21:14:29 +03:00
|
|
|
if (IS_G4X(dev_priv) ||
|
|
|
|
|
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
2017-03-02 19:14:57 +02:00
|
|
|
wm_state = crtc_state->wm;
|
2015-04-21 17:13:21 +03:00
|
|
|
|
2017-03-03 15:46:44 +00:00
|
|
|
/* Keep base drm_crtc_state intact, only clear our extended struct */
|
|
|
|
|
BUILD_BUG_ON(offsetof(struct intel_crtc_state, base));
|
|
|
|
|
memset(&crtc_state->base + 1, 0,
|
|
|
|
|
sizeof(*crtc_state) - sizeof(crtc_state->base));
|
2015-04-21 17:13:21 +03:00
|
|
|
|
2015-04-07 15:28:41 -07:00
|
|
|
crtc_state->scaler_state = scaler_state;
|
2015-04-21 17:13:21 +03:00
|
|
|
crtc_state->shared_dpll = shared_dpll;
|
|
|
|
|
crtc_state->dpll_hw_state = dpll_hw_state;
|
2015-08-05 12:36:59 +02:00
|
|
|
crtc_state->pch_pfit.force_thru = force_thru;
|
2017-08-17 17:55:09 +03:00
|
|
|
crtc_state->ips_force_disable = ips_force_disable;
|
2017-04-21 21:14:29 +03:00
|
|
|
if (IS_G4X(dev_priv) ||
|
|
|
|
|
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
2017-03-02 19:14:57 +02:00
|
|
|
crtc_state->wm = wm_state;
|
2015-03-20 16:18:03 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-21 17:13:02 +03:00
|
|
|
static int
|
2013-03-27 00:44:50 +01:00
|
|
|
intel_modeset_pipe_config(struct drm_crtc *crtc,
|
2015-06-15 12:33:38 +02:00
|
|
|
struct intel_crtc_state *pipe_config)
|
2012-04-20 17:11:53 +01:00
|
|
|
{
|
2015-06-15 12:33:38 +02:00
|
|
|
struct drm_atomic_state *state = pipe_config->base.state;
|
2012-07-08 19:40:39 +02:00
|
|
|
struct intel_encoder *encoder;
|
2015-04-21 17:12:59 +03:00
|
|
|
struct drm_connector *connector;
|
2015-03-20 16:18:08 +02:00
|
|
|
struct drm_connector_state *connector_state;
|
2015-04-10 16:22:37 +02:00
|
|
|
int base_bpp, ret = -EINVAL;
|
2015-03-20 16:18:08 +02:00
|
|
|
int i;
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
bool retry = true;
|
2012-04-20 17:11:53 +01:00
|
|
|
|
2015-03-20 16:18:03 +02:00
|
|
|
clear_intel_crtc_state(pipe_config);
|
2012-07-08 19:40:39 +02:00
|
|
|
|
2013-07-04 12:01:15 +02:00
|
|
|
pipe_config->cpu_transcoder =
|
|
|
|
|
(enum transcoder) to_intel_crtc(crtc)->pipe;
|
2013-03-27 00:44:50 +01:00
|
|
|
|
2013-07-30 13:36:32 +03:00
|
|
|
/*
|
|
|
|
|
* Sanitize sync polarity flags based on requested ones. If neither
|
|
|
|
|
* positive or negative polarity is requested, treat this as meaning
|
|
|
|
|
* negative polarity.
|
|
|
|
|
*/
|
2015-01-15 14:55:22 +02:00
|
|
|
if (!(pipe_config->base.adjusted_mode.flags &
|
2013-07-30 13:36:32 +03:00
|
|
|
(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)))
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC;
|
2013-07-30 13:36:32 +03:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
if (!(pipe_config->base.adjusted_mode.flags &
|
2013-07-30 13:36:32 +03:00
|
|
|
(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
|
2013-07-30 13:36:32 +03:00
|
|
|
|
2015-04-10 16:22:37 +02:00
|
|
|
base_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
|
|
|
|
|
pipe_config);
|
|
|
|
|
if (base_bpp < 0)
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
goto fail;
|
|
|
|
|
|
2013-10-01 22:52:14 +03:00
|
|
|
/*
|
|
|
|
|
* Determine the real pipe dimensions. Note that stereo modes can
|
|
|
|
|
* increase the actual pipe size due to the frame doubling and
|
|
|
|
|
* insertion of additional space for blanks between the frame. This
|
|
|
|
|
* is stored in the crtc timings. We use the requested mode to do this
|
|
|
|
|
* computation to clearly distinguish it from the adjusted mode, which
|
|
|
|
|
* can be changed by the connectors in the below retry loop.
|
|
|
|
|
*/
|
2017-01-25 07:26:56 +01:00
|
|
|
drm_mode_get_hv_timing(&pipe_config->base.mode,
|
2014-12-01 15:40:09 -08:00
|
|
|
&pipe_config->pipe_src_w,
|
|
|
|
|
&pipe_config->pipe_src_h);
|
2013-10-01 22:52:14 +03:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
2016-06-22 21:57:01 +03:00
|
|
|
if (connector_state->crtc != crtc)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
encoder = to_intel_encoder(connector_state->best_encoder);
|
|
|
|
|
|
2016-06-22 21:57:09 +03:00
|
|
|
if (!check_single_encoder_cloning(state, to_intel_crtc(crtc), encoder)) {
|
|
|
|
|
DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-22 21:57:01 +03:00
|
|
|
/*
|
|
|
|
|
* Determine output_types before calling the .compute_config()
|
|
|
|
|
* hooks so that the hooks can use this information safely.
|
|
|
|
|
*/
|
2017-10-27 22:31:24 +03:00
|
|
|
if (encoder->compute_output_type)
|
|
|
|
|
pipe_config->output_types |=
|
|
|
|
|
BIT(encoder->compute_output_type(encoder, pipe_config,
|
|
|
|
|
connector_state));
|
|
|
|
|
else
|
|
|
|
|
pipe_config->output_types |= BIT(encoder->type);
|
2016-06-22 21:57:01 +03:00
|
|
|
}
|
|
|
|
|
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
encoder_retry:
|
2013-06-01 17:17:04 +02:00
|
|
|
/* Ensure the port clock defaults are reset when retrying. */
|
2013-06-01 17:16:21 +02:00
|
|
|
pipe_config->port_clock = 0;
|
2013-06-01 17:17:04 +02:00
|
|
|
pipe_config->pixel_multiplier = 1;
|
2013-06-01 17:16:21 +02:00
|
|
|
|
2013-07-21 21:37:09 +02:00
|
|
|
/* Fill in default crtc timings, allow encoders to overwrite them. */
|
2015-01-15 14:55:22 +02:00
|
|
|
drm_mode_set_crtcinfo(&pipe_config->base.adjusted_mode,
|
|
|
|
|
CRTC_STEREO_DOUBLE);
|
2013-07-21 21:37:09 +02:00
|
|
|
|
2012-07-08 19:40:39 +02:00
|
|
|
/* Pass our mode to the connectors and the CRTC to give them a chance to
|
|
|
|
|
* adjust it according to limitations or connector properties, and also
|
|
|
|
|
* a chance to reject the mode entirely.
|
2010-12-03 15:37:31 +00:00
|
|
|
*/
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
2015-03-20 16:18:08 +02:00
|
|
|
if (connector_state->crtc != crtc)
|
2012-07-08 19:40:39 +02:00
|
|
|
continue;
|
2013-03-27 00:44:52 +01:00
|
|
|
|
2015-03-20 16:18:08 +02:00
|
|
|
encoder = to_intel_encoder(connector_state->best_encoder);
|
|
|
|
|
|
2016-08-09 17:04:05 +02:00
|
|
|
if (!(encoder->compute_config(encoder, pipe_config, connector_state))) {
|
2013-07-21 21:36:59 +02:00
|
|
|
DRM_DEBUG_KMS("Encoder config failure\n");
|
2012-07-08 19:40:39 +02:00
|
|
|
goto fail;
|
|
|
|
|
}
|
2012-04-20 17:11:53 +01:00
|
|
|
}
|
2010-12-03 15:37:31 +00:00
|
|
|
|
2013-06-01 17:16:21 +02:00
|
|
|
/* Set default port clock if not overwritten by the encoder. Needs to be
|
|
|
|
|
* done afterwards in case the encoder adjusts the mode. */
|
|
|
|
|
if (!pipe_config->port_clock)
|
2015-01-15 14:55:22 +02:00
|
|
|
pipe_config->port_clock = pipe_config->base.adjusted_mode.crtc_clock
|
2013-09-25 16:45:37 +01:00
|
|
|
* pipe_config->pixel_multiplier;
|
2013-06-01 17:16:21 +02:00
|
|
|
|
2013-06-07 23:10:32 +02:00
|
|
|
ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config);
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
if (ret < 0) {
|
2012-07-08 19:40:39 +02:00
|
|
|
DRM_DEBUG_KMS("CRTC fixup failed\n");
|
|
|
|
|
goto fail;
|
2012-04-20 17:11:53 +01:00
|
|
|
}
|
drm/i915: implement fdi auto-dithering
So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw
VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit
into this, among them the default 1080p mode.
The solution is to dither down the pipe a bit so that everything fits,
which this patch implements.
But ports compute their state under the assumption that the bpp they
pick will be the one selected, e.g. the display port bw computations
won't work otherwise. Now we could adjust our code to again up-dither
to the computed DP link parameters, but that's pointless.
So instead when the pipe needs to adjust parameters we need to retry
the pipe_config computation at the encoder stage. Furthermore we need
to inform encoders that they should not increase bandwidth
requirements if possible. This is required for the hdmi code, which
prefers the pipe to up-dither to either of the two possible hdmi bpc
values.
LVDS has a similar requirement, although that's probably only
theoretical in nature: It's unlikely that we'll ever see an 8bpc
high-res lvds panel (which is required to hit the 2 fdi lane limit).
eDP is the only thing which could increase the pipe_bpp setting again,
even when in the retry-loop. This could hit the WARN. Two reasons for
not bothering:
- On many eDP panels we'll get a black screen if the bpp settings
don't match vbt. So failing the modeset is the right thing to do.
But since that also means it's the only way to light up the panel,
it should work. So we shouldn't be able to hit this WARN.
- There are still opens around the eDP panel handling, and maybe we
need additional tricks. Before that happens it's imo no use trying
to be too clever.
Worst case we just need to kill that WARN or maybe fail the compute
config stage if the eDP connector can't get the bpp setting it wants.
And since this can only happen with an fdi link in between and so for
pch eDP panels it's rather unlikely to blow up, if ever.
v2: Rebased on top of a bikeshed from Paulo.
v3: Improve commit message around eDP handling with the stuff
things with Imre.
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-21 00:00:16 +01:00
|
|
|
|
|
|
|
|
if (ret == RETRY) {
|
|
|
|
|
if (WARN(!retry, "loop in pipe configuration computation\n")) {
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("CRTC bw constrained, retrying\n");
|
|
|
|
|
retry = false;
|
|
|
|
|
goto encoder_retry;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-12 11:43:34 +02:00
|
|
|
/* Dithering seems to not pass-through bits correctly when it should, so
|
2017-01-24 08:21:49 -08:00
|
|
|
* only enable it on 6bpc panels and when its not a compliance
|
|
|
|
|
* test requesting 6bpc video pattern.
|
|
|
|
|
*/
|
|
|
|
|
pipe_config->dither = (pipe_config->pipe_bpp == 6*3) &&
|
|
|
|
|
!pipe_config->dither_force_disable;
|
2015-08-26 18:57:26 +02:00
|
|
|
DRM_DEBUG_KMS("hw max bpp: %i, pipe bpp: %i, dithering: %i\n",
|
2015-04-10 16:22:37 +02:00
|
|
|
base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
|
drm/i915: precompute pipe bpp before touching the hw
The procedure has now 3 steps:
1. Compute the bpp that the plane will output, this is done in
pipe_config_set_bpp and stored into pipe_config->pipe_bpp. Also,
this function clamps the pipe_bpp to whatever limit the EDID of any
connected output specifies.
2. Adjust the pipe_bpp in the encoder and crtc functions, according to
whatever constraints there are.
3. Decide whether to use dither by comparing the stored plane bpp with
computed pipe_bpp.
There are a few slight functional changes in this patch:
- LVDS connector are now also going through the EDID clamping. But in
a 2nd change we now unconditionally force the lvds bpc value - this
shouldn't matter in reality when the panel setup is consistent, but
better safe than sorry.
- HDMI now forces the pipe_bpp to the selected value - I think that's
what we actually want, since otherwise at least the pixelclock
computations are wrong (I'm not sure whether the port would accept
e.g. 10 bpc when in 12bpc mode). Contrary to the old code, we pick
the next higher bpc value, since otherwise there's no way to make
use of the 12 bpc mode (since the next patch will remove the 12bpc
plane format, it doesn't exist).
Both of these changes are due to the removal of the
pipe_bpp = min(display_bpp, plane_bpp);
statement.
Another slight change is the reworking of the dp bpc code:
- For the mode_valid callback it's sufficient to only check whether
the mode would fit at the lowest bpc.
- The bandwidth computation code is a bit restructured: It now walks
all available bpp values in an outer loop and the codeblock that
computes derived values (once a good configuration is found) has been
moved out of the for loop maze. This is prep work to allow us to
successively fall back on bpc values, and also correctly support bpc
values != 8 or 6.
v2: Rebased on top of Paulo Zanoni's little refactoring to use more
drm dp helper functions.
v3: Rebased on top of Jani's eDP bpp fix and Ville's limited color
range work.
v4: Remove the INTEL_MODE_DP_FORCE_6BPC #define, no longer needed.
v5: Remove intel_crtc->bpp, too, and fix up the 12bpc check in the
hdmi code. Also fixup the bpp check in intel_dp.c, it'll get reworked
in a later patch though again.
v6: Fix spelling in a comment.
v7: Debug output improvements for the bpp computation.
v8: Fixup 6bpc lvds check - dual-link and 8bpc mode are different
things!
v9: Reinstate the fix to properly ignore the firmware edp bpp ... this
was lost in a rebase.
v10: Both g4x and vlv lack 12bpc pipes, so don't enforce that we have
that. Still unsure whether this is the way to go, but at least 6bpc
for a 8bpc hdmi output seems to work.
v11: And g4x/vlv also lack 12bpc hdmi support, so only support high
depth on DP. Adjust the code.
v12: Rebased.
v13: Split out the introduction of pipe_config->dither|pipe_bpp, as
requested from Jesse Barnes.
v14: Split out the special 6BPC handling for DP, as requested by Jesse
Barnes.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-03-27 00:44:58 +01:00
|
|
|
|
2012-07-08 19:40:39 +02:00
|
|
|
fail:
|
2015-04-21 17:13:02 +03:00
|
|
|
return ret;
|
2012-04-20 17:11:53 +01:00
|
|
|
}
|
2010-12-03 15:37:31 +00:00
|
|
|
|
2013-09-06 23:29:02 +03:00
|
|
|
static bool intel_fuzzy_clock_check(int clock1, int clock2)
|
2013-06-27 00:39:25 +03:00
|
|
|
{
|
2013-09-06 23:29:02 +03:00
|
|
|
int diff;
|
2013-06-27 00:39:25 +03:00
|
|
|
|
|
|
|
|
if (clock1 == clock2)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (!clock1 || !clock2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
diff = abs(clock1 - clock2);
|
|
|
|
|
|
|
|
|
|
if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-14 12:17:40 +02:00
|
|
|
static bool
|
|
|
|
|
intel_compare_m_n(unsigned int m, unsigned int n,
|
|
|
|
|
unsigned int m2, unsigned int n2,
|
|
|
|
|
bool exact)
|
|
|
|
|
{
|
|
|
|
|
if (m == m2 && n == n2)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (exact || !m || !n || !m2 || !n2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
BUILD_BUG_ON(DATA_LINK_M_N_MASK > INT_MAX);
|
|
|
|
|
|
2016-01-06 13:54:43 +01:00
|
|
|
if (n > n2) {
|
|
|
|
|
while (n > n2) {
|
2015-07-14 12:17:40 +02:00
|
|
|
m2 <<= 1;
|
|
|
|
|
n2 <<= 1;
|
|
|
|
|
}
|
2016-01-06 13:54:43 +01:00
|
|
|
} else if (n < n2) {
|
|
|
|
|
while (n < n2) {
|
2015-07-14 12:17:40 +02:00
|
|
|
m <<= 1;
|
|
|
|
|
n <<= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-06 13:54:43 +01:00
|
|
|
if (n != n2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return intel_fuzzy_clock_check(m, m2);
|
2015-07-14 12:17:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
intel_compare_link_m_n(const struct intel_link_m_n *m_n,
|
|
|
|
|
struct intel_link_m_n *m2_n2,
|
|
|
|
|
bool adjust)
|
|
|
|
|
{
|
|
|
|
|
if (m_n->tu == m2_n2->tu &&
|
|
|
|
|
intel_compare_m_n(m_n->gmch_m, m_n->gmch_n,
|
|
|
|
|
m2_n2->gmch_m, m2_n2->gmch_n, !adjust) &&
|
|
|
|
|
intel_compare_m_n(m_n->link_m, m_n->link_n,
|
|
|
|
|
m2_n2->link_m, m2_n2->link_n, !adjust)) {
|
|
|
|
|
if (adjust)
|
|
|
|
|
*m2_n2 = *m_n;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 10:50:20 +00:00
|
|
|
static void __printf(3, 4)
|
|
|
|
|
pipe_config_err(bool adjust, const char *name, const char *format, ...)
|
|
|
|
|
{
|
|
|
|
|
char *level;
|
|
|
|
|
unsigned int category;
|
|
|
|
|
struct va_format vaf;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
if (adjust) {
|
|
|
|
|
level = KERN_DEBUG;
|
|
|
|
|
category = DRM_UT_KMS;
|
|
|
|
|
} else {
|
|
|
|
|
level = KERN_ERR;
|
|
|
|
|
category = DRM_UT_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
vaf.fmt = format;
|
|
|
|
|
vaf.va = &args;
|
|
|
|
|
|
|
|
|
|
drm_printk(level, category, "mismatch in %s %pV", name, &vaf);
|
|
|
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-28 10:42:00 +01:00
|
|
|
static bool
|
2016-11-16 12:32:42 +00:00
|
|
|
intel_pipe_config_compare(struct drm_i915_private *dev_priv,
|
2015-01-15 14:55:21 +02:00
|
|
|
struct intel_crtc_state *current_config,
|
2015-07-14 12:17:40 +02:00
|
|
|
struct intel_crtc_state *pipe_config,
|
|
|
|
|
bool adjust)
|
2013-03-28 10:42:00 +01:00
|
|
|
{
|
2015-07-14 12:17:40 +02:00
|
|
|
bool ret = true;
|
2017-11-10 12:34:56 +01:00
|
|
|
bool fixup_inherited = adjust &&
|
|
|
|
|
(current_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED) &&
|
|
|
|
|
!(pipe_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED);
|
2015-07-14 12:17:40 +02:00
|
|
|
|
2013-06-05 13:34:20 +02:00
|
|
|
#define PIPE_CONF_CHECK_X(name) \
|
|
|
|
|
if (current_config->name != pipe_config->name) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
2013-06-05 13:34:20 +02:00
|
|
|
"(expected 0x%08x, found 0x%08x)\n", \
|
|
|
|
|
current_config->name, \
|
|
|
|
|
pipe_config->name); \
|
2015-07-14 12:17:40 +02:00
|
|
|
ret = false; \
|
2013-06-05 13:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-19 11:25:34 +02:00
|
|
|
#define PIPE_CONF_CHECK_I(name) \
|
|
|
|
|
if (current_config->name != pipe_config->name) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
2013-04-19 11:25:34 +02:00
|
|
|
"(expected %i, found %i)\n", \
|
|
|
|
|
current_config->name, \
|
|
|
|
|
pipe_config->name); \
|
2015-07-14 12:17:40 +02:00
|
|
|
ret = false; \
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-10 12:34:55 +01:00
|
|
|
#define PIPE_CONF_CHECK_BOOL(name) \
|
|
|
|
|
if (current_config->name != pipe_config->name) { \
|
|
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
|
|
|
|
"(expected %s, found %s)\n", \
|
|
|
|
|
yesno(current_config->name), \
|
|
|
|
|
yesno(pipe_config->name)); \
|
|
|
|
|
ret = false; \
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-10 12:34:56 +01:00
|
|
|
/*
|
|
|
|
|
* Checks state where we only read out the enabling, but not the entire
|
|
|
|
|
* state itself (like full infoframes or ELD for audio). These states
|
|
|
|
|
* require a full modeset on bootup to fix up.
|
|
|
|
|
*/
|
|
|
|
|
#define PIPE_CONF_CHECK_BOOL_INCOMPLETE(name) \
|
|
|
|
|
if (!fixup_inherited || (!current_config->name && !pipe_config->name)) { \
|
|
|
|
|
PIPE_CONF_CHECK_BOOL(name); \
|
|
|
|
|
} else { \
|
|
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
|
|
|
|
"unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)\n", \
|
|
|
|
|
yesno(current_config->name), \
|
|
|
|
|
yesno(pipe_config->name)); \
|
|
|
|
|
ret = false; \
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
#define PIPE_CONF_CHECK_P(name) \
|
|
|
|
|
if (current_config->name != pipe_config->name) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
2016-03-08 17:46:18 +02:00
|
|
|
"(expected %p, found %p)\n", \
|
|
|
|
|
current_config->name, \
|
|
|
|
|
pipe_config->name); \
|
|
|
|
|
ret = false; \
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-14 12:17:40 +02:00
|
|
|
#define PIPE_CONF_CHECK_M_N(name) \
|
|
|
|
|
if (!intel_compare_link_m_n(¤t_config->name, \
|
|
|
|
|
&pipe_config->name,\
|
|
|
|
|
adjust)) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
2015-07-14 12:17:40 +02:00
|
|
|
"(expected tu %i gmch %i/%i link %i/%i, " \
|
|
|
|
|
"found tu %i, gmch %i/%i link %i/%i)\n", \
|
|
|
|
|
current_config->name.tu, \
|
|
|
|
|
current_config->name.gmch_m, \
|
|
|
|
|
current_config->name.gmch_n, \
|
|
|
|
|
current_config->name.link_m, \
|
|
|
|
|
current_config->name.link_n, \
|
|
|
|
|
pipe_config->name.tu, \
|
|
|
|
|
pipe_config->name.gmch_m, \
|
|
|
|
|
pipe_config->name.gmch_n, \
|
|
|
|
|
pipe_config->name.link_m, \
|
|
|
|
|
pipe_config->name.link_n); \
|
|
|
|
|
ret = false; \
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-30 11:34:36 +02:00
|
|
|
/* This is required for BDW+ where there is only one set of registers for
|
|
|
|
|
* switching between high and low RR.
|
|
|
|
|
* This macro can be used whenever a comparison has to be made between one
|
|
|
|
|
* hw state and multiple sw state variables.
|
|
|
|
|
*/
|
2015-07-14 12:17:40 +02:00
|
|
|
#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) \
|
|
|
|
|
if (!intel_compare_link_m_n(¤t_config->name, \
|
|
|
|
|
&pipe_config->name, adjust) && \
|
|
|
|
|
!intel_compare_link_m_n(¤t_config->alt_name, \
|
|
|
|
|
&pipe_config->name, adjust)) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
2015-07-14 12:17:40 +02:00
|
|
|
"(expected tu %i gmch %i/%i link %i/%i, " \
|
|
|
|
|
"or tu %i gmch %i/%i link %i/%i, " \
|
|
|
|
|
"found tu %i, gmch %i/%i link %i/%i)\n", \
|
|
|
|
|
current_config->name.tu, \
|
|
|
|
|
current_config->name.gmch_m, \
|
|
|
|
|
current_config->name.gmch_n, \
|
|
|
|
|
current_config->name.link_m, \
|
|
|
|
|
current_config->name.link_n, \
|
|
|
|
|
current_config->alt_name.tu, \
|
|
|
|
|
current_config->alt_name.gmch_m, \
|
|
|
|
|
current_config->alt_name.gmch_n, \
|
|
|
|
|
current_config->alt_name.link_m, \
|
|
|
|
|
current_config->alt_name.link_n, \
|
|
|
|
|
pipe_config->name.tu, \
|
|
|
|
|
pipe_config->name.gmch_m, \
|
|
|
|
|
pipe_config->name.gmch_n, \
|
|
|
|
|
pipe_config->name.link_m, \
|
|
|
|
|
pipe_config->name.link_n); \
|
|
|
|
|
ret = false; \
|
2013-03-28 10:42:01 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 21:56:12 +02:00
|
|
|
#define PIPE_CONF_CHECK_FLAGS(name, mask) \
|
|
|
|
|
if ((current_config->name ^ pipe_config->name) & (mask)) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
|
|
|
|
"(%x) (expected %i, found %i)\n", \
|
|
|
|
|
(mask), \
|
2013-04-29 21:56:12 +02:00
|
|
|
current_config->name & (mask), \
|
|
|
|
|
pipe_config->name & (mask)); \
|
2015-07-14 12:17:40 +02:00
|
|
|
ret = false; \
|
2013-04-29 21:56:12 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-06 23:29:07 +03:00
|
|
|
#define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \
|
|
|
|
|
if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \
|
2016-12-06 10:50:20 +00:00
|
|
|
pipe_config_err(adjust, __stringify(name), \
|
2013-09-06 23:29:07 +03:00
|
|
|
"(expected %i, found %i)\n", \
|
|
|
|
|
current_config->name, \
|
|
|
|
|
pipe_config->name); \
|
2015-07-14 12:17:40 +02:00
|
|
|
ret = false; \
|
2013-09-06 23:29:07 +03:00
|
|
|
}
|
|
|
|
|
|
2013-06-06 14:55:52 +02:00
|
|
|
#define PIPE_CONF_QUIRK(quirk) \
|
|
|
|
|
((current_config->quirks | pipe_config->quirks) & (quirk))
|
|
|
|
|
|
2013-05-22 00:50:22 +02:00
|
|
|
PIPE_CONF_CHECK_I(cpu_transcoder);
|
|
|
|
|
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(has_pch_encoder);
|
2013-04-19 11:25:34 +02:00
|
|
|
PIPE_CONF_CHECK_I(fdi_lanes);
|
2015-07-14 12:17:40 +02:00
|
|
|
PIPE_CONF_CHECK_M_N(fdi_m_n);
|
2013-04-19 11:25:34 +02:00
|
|
|
|
2015-07-06 16:39:15 +03:00
|
|
|
PIPE_CONF_CHECK_I(lane_count);
|
2016-06-13 16:44:35 +03:00
|
|
|
PIPE_CONF_CHECK_X(lane_lat_optim_mask);
|
2014-08-05 07:51:23 -07:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 8) {
|
2015-07-14 12:17:40 +02:00
|
|
|
PIPE_CONF_CHECK_M_N(dp_m_n);
|
|
|
|
|
|
|
|
|
|
if (current_config->has_drrs)
|
|
|
|
|
PIPE_CONF_CHECK_M_N(dp_m2_n2);
|
|
|
|
|
} else
|
|
|
|
|
PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2);
|
2013-09-10 17:02:54 +03:00
|
|
|
|
2016-06-22 21:57:01 +03:00
|
|
|
PIPE_CONF_CHECK_X(output_types);
|
2015-11-27 12:21:46 +02:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_start);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_end);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_start);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_end);
|
2013-04-29 21:56:12 +02:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vdisplay);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vtotal);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_start);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_end);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_start);
|
|
|
|
|
PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end);
|
2013-04-29 21:56:12 +02:00
|
|
|
|
2013-06-27 19:47:19 +02:00
|
|
|
PIPE_CONF_CHECK_I(pixel_multiplier);
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
|
2016-10-13 11:03:01 +01:00
|
|
|
if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
|
2016-10-14 10:13:44 +01:00
|
|
|
IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(limited_color_range);
|
drm/i915: enable scrambling
Geminilake platform sports a native HDMI 2.0 controller, and is
capable of driving pixel-clocks upto 594Mhz. HDMI 2.0 spec
mendates scrambling for these higher clocks, for reduced RF footprint.
This patch checks if the monitor supports scrambling, and if required,
enables it during the modeset.
V2: Addressed review comments from Ville:
- Do not track scrambling status in DRM layer, track somewhere in
driver like in intel_crtc_state.
- Don't talk to monitor at such a low layer, set monitor scrambling
in intel_enable_ddi() before enabling the port.
V3: Addressed review comments from Jani
- In comments, function names, use "sink" instead of "monitor",
so that the implementation could be close to the language of
HDMI spec.
V4: Addressed review comment from Maarten
- scrambling -> hdmi_scrambling
- high_tmds_clock_ratio -> hdmi_high_tmds_clock_ratio
V5: Addressed review comments from Ville and Ander
- Do not modifiy the crtc_state after compute_config. Move all
scrambling and tmds_clock_ratio calcutations to compute_config.
- While setting scrambling for source/sink, do not check the
conditions again, just go by the crtc_state flags. This will
simplyfy the condition checks.
V6: Addressed review comments from Ville
- Do not add IS_GLK check in disable/enable function, instead add it
in compute_config, while setting state flags.
- Remove unnecessary paranthesis.
- Simplyfy handle_sink_scrambling function as suggested.
- Add readout code for scrambling status in get_ddi_config and add a
check for the same in pipe_config_compare.
V7: Addressed review comments from Ander/Ville
- No separate function for source scrambling, make it inline
- Align the last line of the macro TRANS_DDI_HDMI_SCRAMBLING_MASK
- Do not add platform check while setting source scrambling
- Use pipe_config instead of crtc->config to set sink scrambling
- To readout scrambling status, Compare with SCRAMBLING_MASK
not any of its bits
- Remove platform check in intel_pipe_config_compare while checking
scrambling status
V8: Fixed mege conflict, Addressed review comments from Ander
- Remove the desciption/comment about scrambling fom the caller, move
it to the function
- Move the IS_GLK check into scrambling function
- Fix alignment
V9: Fixed review comments from Ville, Ander
- Pass the scrambling state variables as bool input to the sink_scrambling
function and let the disable call be unconditional.
- Fix alignments in function calls and debug messages.
- Add kernel doc for function intel_hdmi_handle_sink_scrambling
V10: Rebase
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1489404244-16608-6-git-send-email-shashank.sharma@intel.com
2017-03-13 16:54:03 +05:30
|
|
|
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(hdmi_scrambling);
|
|
|
|
|
PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio);
|
2017-11-10 12:34:56 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_infoframe);
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(ycbcr420);
|
2013-06-06 12:45:25 +02:00
|
|
|
|
2017-11-10 12:34:56 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
|
2014-04-24 23:54:52 +02:00
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
|
2013-04-29 21:56:12 +02:00
|
|
|
DRM_MODE_FLAG_INTERLACE);
|
|
|
|
|
|
2013-06-06 14:55:52 +02:00
|
|
|
if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
|
2013-06-06 14:55:52 +02:00
|
|
|
DRM_MODE_FLAG_PHSYNC);
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
|
2013-06-06 14:55:52 +02:00
|
|
|
DRM_MODE_FLAG_NHSYNC);
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
|
2013-06-06 14:55:52 +02:00
|
|
|
DRM_MODE_FLAG_PVSYNC);
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
|
2013-06-06 14:55:52 +02:00
|
|
|
DRM_MODE_FLAG_NVSYNC);
|
|
|
|
|
}
|
2013-05-14 17:08:26 -07:00
|
|
|
|
2015-09-03 21:50:16 +03:00
|
|
|
PIPE_CONF_CHECK_X(gmch_pfit.control);
|
2015-07-15 14:15:50 +02:00
|
|
|
/* pfit ratios are autocomputed by the hw on gen4+ */
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 4)
|
2016-03-15 16:40:07 +02:00
|
|
|
PIPE_CONF_CHECK_X(gmch_pfit.pgm_ratios);
|
2015-09-03 21:50:16 +03:00
|
|
|
PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits);
|
2014-04-13 12:00:33 +02:00
|
|
|
|
2015-08-27 15:44:05 +02:00
|
|
|
if (!adjust) {
|
|
|
|
|
PIPE_CONF_CHECK_I(pipe_src_w);
|
|
|
|
|
PIPE_CONF_CHECK_I(pipe_src_h);
|
|
|
|
|
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(pch_pfit.enabled);
|
2015-08-27 15:44:05 +02:00
|
|
|
if (current_config->pch_pfit.enabled) {
|
|
|
|
|
PIPE_CONF_CHECK_X(pch_pfit.pos);
|
|
|
|
|
PIPE_CONF_CHECK_X(pch_pfit.size);
|
|
|
|
|
}
|
2013-05-07 23:34:16 +02:00
|
|
|
|
2015-09-14 11:30:10 +02:00
|
|
|
PIPE_CONF_CHECK_I(scaler_state.scaler_id);
|
2017-01-26 21:50:31 +02:00
|
|
|
PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate);
|
2015-09-14 11:30:10 +02:00
|
|
|
}
|
2015-04-07 15:28:45 -07:00
|
|
|
|
2017-11-10 12:34:55 +01:00
|
|
|
PIPE_CONF_CHECK_BOOL(double_wide);
|
2013-09-04 18:30:03 +03:00
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
PIPE_CONF_CHECK_P(shared_dpll);
|
2013-06-05 13:34:20 +02:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
|
2013-06-05 13:34:28 +02:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
|
2013-06-05 13:34:20 +02:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
|
2014-07-04 11:27:39 -03:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
|
2015-11-16 14:42:12 +01:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.spll);
|
2014-11-13 14:55:21 +00:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
|
2017-09-22 17:53:42 -03:00
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
|
|
|
|
|
PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
|
2013-06-07 23:11:08 +02:00
|
|
|
|
2016-04-12 22:14:35 +03:00
|
|
|
PIPE_CONF_CHECK_X(dsi_pll.ctrl);
|
|
|
|
|
PIPE_CONF_CHECK_X(dsi_pll.div);
|
|
|
|
|
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5)
|
2013-09-06 23:29:00 +03:00
|
|
|
PIPE_CONF_CHECK_I(pipe_bpp);
|
|
|
|
|
|
2015-01-15 14:55:22 +02:00
|
|
|
PIPE_CONF_CHECK_CLOCK_FUZZY(base.adjusted_mode.crtc_clock);
|
2014-01-20 14:18:04 -08:00
|
|
|
PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
|
2013-09-06 23:29:07 +03:00
|
|
|
|
2017-10-24 12:52:14 +03:00
|
|
|
PIPE_CONF_CHECK_I(min_voltage_level);
|
|
|
|
|
|
2013-06-05 13:34:20 +02:00
|
|
|
#undef PIPE_CONF_CHECK_X
|
2013-04-19 11:25:34 +02:00
|
|
|
#undef PIPE_CONF_CHECK_I
|
2017-11-10 12:34:55 +01:00
|
|
|
#undef PIPE_CONF_CHECK_BOOL
|
2017-11-10 12:34:56 +01:00
|
|
|
#undef PIPE_CONF_CHECK_BOOL_INCOMPLETE
|
2016-03-08 17:46:18 +02:00
|
|
|
#undef PIPE_CONF_CHECK_P
|
2013-04-29 21:56:12 +02:00
|
|
|
#undef PIPE_CONF_CHECK_FLAGS
|
2013-09-06 23:29:07 +03:00
|
|
|
#undef PIPE_CONF_CHECK_CLOCK_FUZZY
|
2013-06-06 14:55:52 +02:00
|
|
|
#undef PIPE_CONF_QUIRK
|
2013-03-28 10:42:01 +01:00
|
|
|
|
2015-07-14 12:17:40 +02:00
|
|
|
return ret;
|
2013-03-28 10:42:00 +01:00
|
|
|
}
|
|
|
|
|
|
2016-02-17 21:41:09 +02:00
|
|
|
static void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv,
|
|
|
|
|
const struct intel_crtc_state *pipe_config)
|
|
|
|
|
{
|
|
|
|
|
if (pipe_config->has_pch_encoder) {
|
2016-02-17 21:41:10 +02:00
|
|
|
int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config),
|
2016-02-17 21:41:09 +02:00
|
|
|
&pipe_config->fdi_m_n);
|
|
|
|
|
int dotclock = pipe_config->base.adjusted_mode.crtc_clock;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* FDI already provided one idea for the dotclock.
|
|
|
|
|
* Yell if the encoder disagrees.
|
|
|
|
|
*/
|
|
|
|
|
WARN(!intel_fuzzy_clock_check(fdi_dotclock, dotclock),
|
|
|
|
|
"FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
|
|
|
|
|
fdi_dotclock, dotclock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-30 10:00:05 +02:00
|
|
|
static void verify_wm_state(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *new_state)
|
2014-11-04 17:06:52 +00:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2014-11-04 17:06:52 +00:00
|
|
|
struct skl_ddb_allocation hw_ddb, *sw_ddb;
|
2016-10-14 17:31:57 -04:00
|
|
|
struct skl_pipe_wm hw_wm, *sw_wm;
|
|
|
|
|
struct skl_plane_wm *hw_plane_wm, *sw_plane_wm;
|
|
|
|
|
struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry;
|
2016-03-23 14:58:06 +01:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
const enum pipe pipe = intel_crtc->pipe;
|
2016-10-14 17:31:57 -04:00
|
|
|
int plane, level, max_level = ilk_wm_max_level(dev_priv);
|
2014-11-04 17:06:52 +00:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 9 || !new_state->active)
|
2014-11-04 17:06:52 +00:00
|
|
|
return;
|
|
|
|
|
|
2016-10-14 17:31:57 -04:00
|
|
|
skl_pipe_wm_get_hw_state(crtc, &hw_wm);
|
2016-10-26 15:41:36 +02:00
|
|
|
sw_wm = &to_intel_crtc_state(new_state)->wm.skl.optimal;
|
2016-10-14 17:31:57 -04:00
|
|
|
|
2014-11-04 17:06:52 +00:00
|
|
|
skl_ddb_get_hw_state(dev_priv, &hw_ddb);
|
|
|
|
|
sw_ddb = &dev_priv->wm.skl_hw.ddb;
|
|
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
/* planes */
|
2016-10-26 15:51:28 -07:00
|
|
|
for_each_universal_plane(dev_priv, pipe, plane) {
|
2016-10-14 17:31:57 -04:00
|
|
|
hw_plane_wm = &hw_wm.planes[plane];
|
|
|
|
|
sw_plane_wm = &sw_wm->planes[plane];
|
2014-11-04 17:06:52 +00:00
|
|
|
|
2016-10-14 17:31:57 -04:00
|
|
|
/* Watermarks */
|
|
|
|
|
for (level = 0; level <= max_level; level++) {
|
|
|
|
|
if (skl_wm_level_equals(&hw_plane_wm->wm[level],
|
|
|
|
|
&sw_plane_wm->wm[level]))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
DRM_ERROR("mismatch in WM pipe %c plane %d level %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
|
|
|
|
|
pipe_name(pipe), plane + 1, level,
|
|
|
|
|
sw_plane_wm->wm[level].plane_en,
|
|
|
|
|
sw_plane_wm->wm[level].plane_res_b,
|
|
|
|
|
sw_plane_wm->wm[level].plane_res_l,
|
|
|
|
|
hw_plane_wm->wm[level].plane_en,
|
|
|
|
|
hw_plane_wm->wm[level].plane_res_b,
|
|
|
|
|
hw_plane_wm->wm[level].plane_res_l);
|
|
|
|
|
}
|
2014-11-04 17:06:52 +00:00
|
|
|
|
2016-10-14 17:31:57 -04:00
|
|
|
if (!skl_wm_level_equals(&hw_plane_wm->trans_wm,
|
|
|
|
|
&sw_plane_wm->trans_wm)) {
|
|
|
|
|
DRM_ERROR("mismatch in trans WM pipe %c plane %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
|
|
|
|
|
pipe_name(pipe), plane + 1,
|
|
|
|
|
sw_plane_wm->trans_wm.plane_en,
|
|
|
|
|
sw_plane_wm->trans_wm.plane_res_b,
|
|
|
|
|
sw_plane_wm->trans_wm.plane_res_l,
|
|
|
|
|
hw_plane_wm->trans_wm.plane_en,
|
|
|
|
|
hw_plane_wm->trans_wm.plane_res_b,
|
|
|
|
|
hw_plane_wm->trans_wm.plane_res_l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* DDB */
|
|
|
|
|
hw_ddb_entry = &hw_ddb.plane[pipe][plane];
|
|
|
|
|
sw_ddb_entry = &sw_ddb->plane[pipe][plane];
|
|
|
|
|
|
|
|
|
|
if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
|
2016-10-14 17:31:58 -04:00
|
|
|
DRM_ERROR("mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n",
|
2016-10-14 17:31:57 -04:00
|
|
|
pipe_name(pipe), plane + 1,
|
|
|
|
|
sw_ddb_entry->start, sw_ddb_entry->end,
|
|
|
|
|
hw_ddb_entry->start, hw_ddb_entry->end);
|
|
|
|
|
}
|
2016-03-23 14:58:06 +01:00
|
|
|
}
|
2014-11-04 17:06:52 +00:00
|
|
|
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
/*
|
|
|
|
|
* cursor
|
|
|
|
|
* If the cursor plane isn't active, we may not have updated it's ddb
|
|
|
|
|
* allocation. In that case since the ddb allocation will be updated
|
|
|
|
|
* once the plane becomes visible, we can skip this check
|
|
|
|
|
*/
|
2017-03-27 21:55:35 +03:00
|
|
|
if (1) {
|
2016-10-14 17:31:57 -04:00
|
|
|
hw_plane_wm = &hw_wm.planes[PLANE_CURSOR];
|
|
|
|
|
sw_plane_wm = &sw_wm->planes[PLANE_CURSOR];
|
|
|
|
|
|
|
|
|
|
/* Watermarks */
|
|
|
|
|
for (level = 0; level <= max_level; level++) {
|
|
|
|
|
if (skl_wm_level_equals(&hw_plane_wm->wm[level],
|
|
|
|
|
&sw_plane_wm->wm[level]))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
DRM_ERROR("mismatch in WM pipe %c cursor level %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
|
|
|
|
|
pipe_name(pipe), level,
|
|
|
|
|
sw_plane_wm->wm[level].plane_en,
|
|
|
|
|
sw_plane_wm->wm[level].plane_res_b,
|
|
|
|
|
sw_plane_wm->wm[level].plane_res_l,
|
|
|
|
|
hw_plane_wm->wm[level].plane_en,
|
|
|
|
|
hw_plane_wm->wm[level].plane_res_b,
|
|
|
|
|
hw_plane_wm->wm[level].plane_res_l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!skl_wm_level_equals(&hw_plane_wm->trans_wm,
|
|
|
|
|
&sw_plane_wm->trans_wm)) {
|
|
|
|
|
DRM_ERROR("mismatch in trans WM pipe %c cursor (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n",
|
|
|
|
|
pipe_name(pipe),
|
|
|
|
|
sw_plane_wm->trans_wm.plane_en,
|
|
|
|
|
sw_plane_wm->trans_wm.plane_res_b,
|
|
|
|
|
sw_plane_wm->trans_wm.plane_res_l,
|
|
|
|
|
hw_plane_wm->trans_wm.plane_en,
|
|
|
|
|
hw_plane_wm->trans_wm.plane_res_b,
|
|
|
|
|
hw_plane_wm->trans_wm.plane_res_l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* DDB */
|
|
|
|
|
hw_ddb_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
|
|
|
|
|
sw_ddb_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
|
2016-10-14 17:31:57 -04:00
|
|
|
if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) {
|
2016-10-14 17:31:58 -04:00
|
|
|
DRM_ERROR("mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n",
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
pipe_name(pipe),
|
2016-10-14 17:31:57 -04:00
|
|
|
sw_ddb_entry->start, sw_ddb_entry->end,
|
|
|
|
|
hw_ddb_entry->start, hw_ddb_entry->end);
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
}
|
2014-11-04 17:06:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-05 13:34:18 +02:00
|
|
|
static void
|
2016-11-08 13:55:41 +01:00
|
|
|
verify_connector_state(struct drm_device *dev,
|
|
|
|
|
struct drm_atomic_state *state,
|
|
|
|
|
struct drm_crtc *crtc)
|
2012-07-10 09:50:11 +02:00
|
|
|
{
|
2015-08-06 13:49:22 +02:00
|
|
|
struct drm_connector *connector;
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_connector_state *new_conn_state;
|
2016-11-08 13:55:41 +01:00
|
|
|
int i;
|
2012-07-10 09:50:11 +02:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_connector_in_state(state, connector, new_conn_state, i) {
|
2015-08-06 13:49:22 +02:00
|
|
|
struct drm_encoder *encoder = connector->encoder;
|
2017-05-11 10:28:43 +02:00
|
|
|
struct drm_crtc_state *crtc_state = NULL;
|
2015-07-13 16:30:26 +02:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
if (new_conn_state->crtc != crtc)
|
2016-03-23 14:58:06 +01:00
|
|
|
continue;
|
|
|
|
|
|
2017-05-11 10:28:43 +02:00
|
|
|
if (crtc)
|
|
|
|
|
crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
|
|
|
|
|
|
|
|
|
|
intel_connector_verify_state(crtc_state, new_conn_state);
|
2012-07-10 09:50:11 +02:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
I915_STATE_WARN(new_conn_state->best_encoder != encoder,
|
2015-08-06 13:49:22 +02:00
|
|
|
"connector's atomic encoder doesn't match legacy encoder\n");
|
2012-07-10 09:50:11 +02:00
|
|
|
}
|
2013-06-05 13:34:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2017-03-01 10:52:26 +01:00
|
|
|
verify_encoder_state(struct drm_device *dev, struct drm_atomic_state *state)
|
2013-06-05 13:34:18 +02:00
|
|
|
{
|
|
|
|
|
struct intel_encoder *encoder;
|
2017-03-01 10:52:26 +01:00
|
|
|
struct drm_connector *connector;
|
|
|
|
|
struct drm_connector_state *old_conn_state, *new_conn_state;
|
|
|
|
|
int i;
|
2012-07-10 09:50:11 +02:00
|
|
|
|
2014-08-05 11:29:37 +01:00
|
|
|
for_each_intel_encoder(dev, encoder) {
|
2017-03-01 10:52:26 +01:00
|
|
|
bool enabled = false, found = false;
|
2015-08-05 12:37:05 +02:00
|
|
|
enum pipe pipe;
|
2012-07-10 09:50:11 +02:00
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("[ENCODER:%d:%s]\n",
|
|
|
|
|
encoder->base.base.id,
|
2014-06-03 14:56:21 +03:00
|
|
|
encoder->base.name);
|
2012-07-10 09:50:11 +02:00
|
|
|
|
2017-03-01 10:52:26 +01:00
|
|
|
for_each_oldnew_connector_in_state(state, connector, old_conn_state,
|
|
|
|
|
new_conn_state, i) {
|
|
|
|
|
if (old_conn_state->best_encoder == &encoder->base)
|
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
|
|
if (new_conn_state->best_encoder != &encoder->base)
|
2012-07-10 09:50:11 +02:00
|
|
|
continue;
|
2017-03-01 10:52:26 +01:00
|
|
|
found = enabled = true;
|
2015-07-13 16:30:26 +02:00
|
|
|
|
2017-03-01 10:52:26 +01:00
|
|
|
I915_STATE_WARN(new_conn_state->crtc !=
|
2015-07-13 16:30:26 +02:00
|
|
|
encoder->base.crtc,
|
|
|
|
|
"connector's crtc doesn't match encoder crtc\n");
|
2012-07-10 09:50:11 +02:00
|
|
|
}
|
2017-03-01 10:52:26 +01:00
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
continue;
|
2014-05-02 14:02:48 +10:00
|
|
|
|
2014-12-15 13:56:32 -05:00
|
|
|
I915_STATE_WARN(!!encoder->base.crtc != enabled,
|
2012-07-10 09:50:11 +02:00
|
|
|
"encoder's enabled state mismatch "
|
|
|
|
|
"(expected %i, found %i)\n",
|
|
|
|
|
!!encoder->base.crtc, enabled);
|
2015-08-05 12:37:04 +02:00
|
|
|
|
|
|
|
|
if (!encoder->base.crtc) {
|
2015-08-05 12:37:05 +02:00
|
|
|
bool active;
|
2015-08-05 12:37:04 +02:00
|
|
|
|
2015-08-05 12:37:05 +02:00
|
|
|
active = encoder->get_hw_state(encoder, &pipe);
|
|
|
|
|
I915_STATE_WARN(active,
|
|
|
|
|
"encoder detached but still enabled on pipe %c.\n",
|
|
|
|
|
pipe_name(pipe));
|
2015-08-05 12:37:04 +02:00
|
|
|
}
|
2012-07-10 09:50:11 +02:00
|
|
|
}
|
2013-06-05 13:34:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_crtc_state(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *old_crtc_state,
|
|
|
|
|
struct drm_crtc_state *new_crtc_state)
|
2013-06-05 13:34:18 +02:00
|
|
|
{
|
2016-03-23 14:58:06 +01:00
|
|
|
struct drm_device *dev = crtc->dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-06-05 13:34:18 +02:00
|
|
|
struct intel_encoder *encoder;
|
2016-03-23 14:58:06 +01:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
struct intel_crtc_state *pipe_config, *sw_config;
|
|
|
|
|
struct drm_atomic_state *old_state;
|
|
|
|
|
bool active;
|
2013-05-14 17:08:26 -07:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
old_state = old_crtc_state->state;
|
2016-05-09 16:34:09 +02:00
|
|
|
__drm_atomic_helper_crtc_destroy_state(old_crtc_state);
|
2016-03-23 14:58:06 +01:00
|
|
|
pipe_config = to_intel_crtc_state(old_crtc_state);
|
|
|
|
|
memset(pipe_config, 0, sizeof(*pipe_config));
|
|
|
|
|
pipe_config->base.crtc = crtc;
|
|
|
|
|
pipe_config->base.state = old_state;
|
2012-07-10 09:50:11 +02:00
|
|
|
|
2016-05-27 20:59:19 +03:00
|
|
|
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
|
2012-07-10 09:50:11 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
active = dev_priv->display.get_pipe_config(intel_crtc, pipe_config);
|
2013-05-29 10:41:29 +02:00
|
|
|
|
2017-06-01 17:36:19 +03:00
|
|
|
/* we keep both pipes enabled on 830 */
|
|
|
|
|
if (IS_I830(dev_priv))
|
2016-03-23 14:58:06 +01:00
|
|
|
active = new_crtc_state->active;
|
2013-06-06 12:45:25 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
I915_STATE_WARN(new_crtc_state->active != active,
|
|
|
|
|
"crtc active state doesn't match with hw state "
|
|
|
|
|
"(expected %i, found %i)\n", new_crtc_state->active, active);
|
2013-03-28 10:42:00 +01:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
I915_STATE_WARN(intel_crtc->active != new_crtc_state->active,
|
|
|
|
|
"transitional active state does not match atomic hw state "
|
|
|
|
|
"(expected %i, found %i)\n", new_crtc_state->active, intel_crtc->active);
|
2015-08-05 12:37:05 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
for_each_encoder_on_crtc(dev, crtc, encoder) {
|
|
|
|
|
enum pipe pipe;
|
2015-08-05 12:37:05 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
active = encoder->get_hw_state(encoder, &pipe);
|
|
|
|
|
I915_STATE_WARN(active != new_crtc_state->active,
|
|
|
|
|
"[ENCODER:%i] active %i with crtc active %i\n",
|
|
|
|
|
encoder->base.base.id, active, new_crtc_state->active);
|
2015-08-05 12:37:05 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
I915_STATE_WARN(active && intel_crtc->pipe != pipe,
|
|
|
|
|
"Encoder connected to wrong pipe %c\n",
|
|
|
|
|
pipe_name(pipe));
|
2015-08-05 12:37:05 +02:00
|
|
|
|
2017-10-27 22:31:23 +03:00
|
|
|
if (active)
|
2016-03-23 14:58:06 +01:00
|
|
|
encoder->get_config(encoder, pipe_config);
|
|
|
|
|
}
|
2015-06-01 12:49:52 +02:00
|
|
|
|
2017-01-26 21:50:31 +02:00
|
|
|
intel_crtc_compute_pixel_rate(pipe_config);
|
|
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
if (!new_crtc_state->active)
|
|
|
|
|
return;
|
2015-07-14 12:17:40 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
intel_pipe_config_sanity_check(dev_priv, pipe_config);
|
2016-02-17 21:41:09 +02:00
|
|
|
|
2017-05-11 10:28:43 +02:00
|
|
|
sw_config = to_intel_crtc_state(new_crtc_state);
|
2016-11-16 12:32:42 +00:00
|
|
|
if (!intel_pipe_config_compare(dev_priv, sw_config,
|
2016-03-23 14:58:06 +01:00
|
|
|
pipe_config, false)) {
|
|
|
|
|
I915_STATE_WARN(1, "pipe state doesn't match!\n");
|
|
|
|
|
intel_dump_pipe_config(intel_crtc, pipe_config,
|
|
|
|
|
"[hw state]");
|
|
|
|
|
intel_dump_pipe_config(intel_crtc, sw_config,
|
|
|
|
|
"[sw state]");
|
2012-07-10 09:50:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:17 +02:00
|
|
|
static void
|
|
|
|
|
intel_verify_planes(struct intel_atomic_state *state)
|
|
|
|
|
{
|
|
|
|
|
struct intel_plane *plane;
|
|
|
|
|
const struct intel_plane_state *plane_state;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for_each_new_intel_plane_in_state(state, plane,
|
|
|
|
|
plane_state, i)
|
|
|
|
|
assert_plane(plane, plane_state->base.visible);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-05 13:34:18 +02:00
|
|
|
static void
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_single_dpll_state(struct drm_i915_private *dev_priv,
|
|
|
|
|
struct intel_shared_dpll *pll,
|
|
|
|
|
struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *new_state)
|
2013-06-05 13:34:18 +02:00
|
|
|
{
|
|
|
|
|
struct intel_dpll_hw_state dpll_hw_state;
|
2016-03-23 14:58:06 +01:00
|
|
|
unsigned crtc_mask;
|
|
|
|
|
bool active;
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
DRM_DEBUG_KMS("%s\n", pll->name);
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
active = pll->funcs.get_hw_state(dev_priv, pll, &dpll_hw_state);
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
if (!(pll->flags & INTEL_DPLL_ALWAYS_ON)) {
|
|
|
|
|
I915_STATE_WARN(!pll->on && pll->active_mask,
|
|
|
|
|
"pll in active use but not on in sw tracking\n");
|
|
|
|
|
I915_STATE_WARN(pll->on && !pll->active_mask,
|
|
|
|
|
"pll is on but not used by any active crtc\n");
|
|
|
|
|
I915_STATE_WARN(pll->on != active,
|
|
|
|
|
"pll on state mismatch (expected %i, found %i)\n",
|
|
|
|
|
pll->on, active);
|
|
|
|
|
}
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
if (!crtc) {
|
2016-12-29 17:22:09 +02:00
|
|
|
I915_STATE_WARN(pll->active_mask & ~pll->state.crtc_mask,
|
2016-03-23 14:58:06 +01:00
|
|
|
"more active pll users than references: %x vs %x\n",
|
2016-12-29 17:22:09 +02:00
|
|
|
pll->active_mask, pll->state.crtc_mask);
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crtc_mask = 1 << drm_crtc_index(crtc);
|
|
|
|
|
|
|
|
|
|
if (new_state->active)
|
|
|
|
|
I915_STATE_WARN(!(pll->active_mask & crtc_mask),
|
|
|
|
|
"pll active mismatch (expected pipe %c in active mask 0x%02x)\n",
|
|
|
|
|
pipe_name(drm_crtc_index(crtc)), pll->active_mask);
|
|
|
|
|
else
|
|
|
|
|
I915_STATE_WARN(pll->active_mask & crtc_mask,
|
|
|
|
|
"pll active mismatch (didn't expect pipe %c in active mask 0x%02x)\n",
|
|
|
|
|
pipe_name(drm_crtc_index(crtc)), pll->active_mask);
|
2016-03-14 09:27:52 +01:00
|
|
|
|
2016-12-29 17:22:09 +02:00
|
|
|
I915_STATE_WARN(!(pll->state.crtc_mask & crtc_mask),
|
2016-03-23 14:58:06 +01:00
|
|
|
"pll enabled crtcs mismatch (expected 0x%x in 0x%02x)\n",
|
2016-12-29 17:22:09 +02:00
|
|
|
crtc_mask, pll->state.crtc_mask);
|
2013-06-05 13:34:20 +02:00
|
|
|
|
2016-12-29 17:22:09 +02:00
|
|
|
I915_STATE_WARN(pll->on && memcmp(&pll->state.hw_state,
|
2016-03-23 14:58:06 +01:00
|
|
|
&dpll_hw_state,
|
|
|
|
|
sizeof(dpll_hw_state)),
|
|
|
|
|
"pll hw state mismatch\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_shared_dpll_state(struct drm_device *dev, struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *old_crtc_state,
|
|
|
|
|
struct drm_crtc_state *new_crtc_state)
|
2016-03-23 14:58:06 +01:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-23 14:58:06 +01:00
|
|
|
struct intel_crtc_state *old_state = to_intel_crtc_state(old_crtc_state);
|
|
|
|
|
struct intel_crtc_state *new_state = to_intel_crtc_state(new_crtc_state);
|
|
|
|
|
|
|
|
|
|
if (new_state->shared_dpll)
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_single_dpll_state(dev_priv, new_state->shared_dpll, crtc, new_crtc_state);
|
2016-03-23 14:58:06 +01:00
|
|
|
|
|
|
|
|
if (old_state->shared_dpll &&
|
|
|
|
|
old_state->shared_dpll != new_state->shared_dpll) {
|
|
|
|
|
unsigned crtc_mask = 1 << drm_crtc_index(crtc);
|
|
|
|
|
struct intel_shared_dpll *pll = old_state->shared_dpll;
|
|
|
|
|
|
|
|
|
|
I915_STATE_WARN(pll->active_mask & crtc_mask,
|
|
|
|
|
"pll active mismatch (didn't expect pipe %c in active mask)\n",
|
|
|
|
|
pipe_name(drm_crtc_index(crtc)));
|
2016-12-29 17:22:09 +02:00
|
|
|
I915_STATE_WARN(pll->state.crtc_mask & crtc_mask,
|
2016-03-23 14:58:06 +01:00
|
|
|
"pll enabled crtcs mismatch (found %x in enabled mask)\n",
|
|
|
|
|
pipe_name(drm_crtc_index(crtc)));
|
2013-06-05 13:34:16 +02:00
|
|
|
}
|
2012-07-10 09:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-23 14:58:06 +01:00
|
|
|
static void
|
2016-03-30 10:00:05 +02:00
|
|
|
intel_modeset_verify_crtc(struct drm_crtc *crtc,
|
2016-11-08 13:55:41 +01:00
|
|
|
struct drm_atomic_state *state,
|
|
|
|
|
struct drm_crtc_state *old_state,
|
|
|
|
|
struct drm_crtc_state *new_state)
|
2016-03-23 14:58:06 +01:00
|
|
|
{
|
2016-05-24 17:13:53 +02:00
|
|
|
if (!needs_modeset(new_state) &&
|
|
|
|
|
!to_intel_crtc_state(new_state)->update_pipe)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_wm_state(crtc, new_state);
|
2016-11-08 13:55:41 +01:00
|
|
|
verify_connector_state(crtc->dev, state, crtc);
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_crtc_state(crtc, old_state, new_state);
|
|
|
|
|
verify_shared_dpll_state(crtc->dev, crtc, old_state, new_state);
|
2016-03-23 14:58:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_disabled_dpll_state(struct drm_device *dev)
|
2016-03-23 14:58:06 +01:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-23 14:58:06 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < dev_priv->num_shared_dpll; i++)
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_single_dpll_state(dev_priv, &dev_priv->shared_dplls[i], NULL, NULL);
|
2016-03-23 14:58:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2016-11-08 13:55:41 +01:00
|
|
|
intel_modeset_verify_disabled(struct drm_device *dev,
|
|
|
|
|
struct drm_atomic_state *state)
|
2016-03-23 14:58:06 +01:00
|
|
|
{
|
2017-03-01 10:52:26 +01:00
|
|
|
verify_encoder_state(dev, state);
|
2016-11-08 13:55:41 +01:00
|
|
|
verify_connector_state(dev, state, NULL);
|
2016-03-30 10:00:05 +02:00
|
|
|
verify_disabled_dpll_state(dev);
|
2016-03-23 14:58:06 +01:00
|
|
|
}
|
|
|
|
|
|
2014-05-15 20:23:23 +03:00
|
|
|
static void update_scanline_offset(struct intel_crtc *crtc)
|
|
|
|
|
{
|
2016-10-13 11:02:52 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2014-05-15 20:23:23 +03:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The scanline counter increments at the leading edge of hsync.
|
|
|
|
|
*
|
|
|
|
|
* On most platforms it starts counting from vtotal-1 on the
|
|
|
|
|
* first active line. That means the scanline counter value is
|
|
|
|
|
* always one less than what we would expect. Ie. just after
|
|
|
|
|
* start of vblank, which also occurs at start of hsync (on the
|
|
|
|
|
* last active line), the scanline counter will read vblank_start-1.
|
|
|
|
|
*
|
|
|
|
|
* On gen2 the scanline counter starts counting from 1 instead
|
|
|
|
|
* of vtotal-1, so we have to subtract one (or rather add vtotal-1
|
|
|
|
|
* to keep the value positive), instead of adding one.
|
|
|
|
|
*
|
|
|
|
|
* On HSW+ the behaviour of the scanline counter depends on the output
|
|
|
|
|
* type. For DP ports it behaves like most other platforms, but on HDMI
|
|
|
|
|
* there's an extra 1 line difference. So we need to add two instead of
|
|
|
|
|
* one to the value.
|
2016-12-15 19:47:34 +02:00
|
|
|
*
|
|
|
|
|
* On VLV/CHV DSI the scanline counter would appear to increment
|
|
|
|
|
* approx. 1/3 of a scanline before start of vblank. Unfortunately
|
|
|
|
|
* that means we can't tell whether we're in vblank or not while
|
|
|
|
|
* we're on that particular line. We must still set scanline_offset
|
|
|
|
|
* to 1 so that the vblank timestamps come out correct when we query
|
|
|
|
|
* the scanline counter from within the vblank interrupt handler.
|
|
|
|
|
* However if queried just before the start of vblank we'll get an
|
|
|
|
|
* answer that's slightly in the future.
|
2014-05-15 20:23:23 +03:00
|
|
|
*/
|
2016-10-13 11:02:52 +01:00
|
|
|
if (IS_GEN2(dev_priv)) {
|
2015-09-08 13:40:45 +03:00
|
|
|
const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
|
2014-05-15 20:23:23 +03:00
|
|
|
int vtotal;
|
|
|
|
|
|
2015-09-08 13:40:45 +03:00
|
|
|
vtotal = adjusted_mode->crtc_vtotal;
|
|
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
|
2014-05-15 20:23:23 +03:00
|
|
|
vtotal /= 2;
|
|
|
|
|
|
|
|
|
|
crtc->scanline_offset = vtotal - 1;
|
2016-10-13 11:02:52 +01:00
|
|
|
} else if (HAS_DDI(dev_priv) &&
|
2016-06-22 21:57:02 +03:00
|
|
|
intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
|
2014-05-15 20:23:23 +03:00
|
|
|
crtc->scanline_offset = 2;
|
|
|
|
|
} else
|
|
|
|
|
crtc->scanline_offset = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 12:33:42 +02:00
|
|
|
static void intel_modeset_clear_plls(struct drm_atomic_state *state)
|
2015-01-29 16:55:08 +02:00
|
|
|
{
|
2015-04-02 14:47:57 +03:00
|
|
|
struct drm_device *dev = state->dev;
|
2015-01-29 16:55:08 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-04-21 17:13:04 +03:00
|
|
|
struct drm_crtc *crtc;
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
2015-04-21 17:13:04 +03:00
|
|
|
int i;
|
2015-01-29 16:55:08 +02:00
|
|
|
|
|
|
|
|
if (!dev_priv->display.crtc_compute_clock)
|
2015-06-15 12:33:42 +02:00
|
|
|
return;
|
2015-01-29 16:55:08 +02:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
2016-02-09 13:02:17 +01:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2016-03-08 17:46:18 +02:00
|
|
|
struct intel_shared_dpll *old_dpll =
|
2017-03-09 15:52:04 +01:00
|
|
|
to_intel_crtc_state(old_crtc_state)->shared_dpll;
|
2015-04-21 17:13:04 +03:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
if (!needs_modeset(new_crtc_state))
|
2015-04-02 14:47:57 +03:00
|
|
|
continue;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
to_intel_crtc_state(new_crtc_state)->shared_dpll = NULL;
|
2016-02-09 13:02:17 +01:00
|
|
|
|
2016-03-08 17:46:18 +02:00
|
|
|
if (!old_dpll)
|
2016-02-09 13:02:17 +01:00
|
|
|
continue;
|
2015-04-21 17:13:04 +03:00
|
|
|
|
2016-12-29 17:22:07 +02:00
|
|
|
intel_release_shared_dpll(old_dpll, intel_crtc, state);
|
2015-06-15 12:33:42 +02:00
|
|
|
}
|
2015-01-29 16:55:08 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-01 12:50:09 +02:00
|
|
|
/*
|
|
|
|
|
* This implements the workaround described in the "notes" section of the mode
|
|
|
|
|
* set sequence documentation. When going from no pipes or single pipe to
|
|
|
|
|
* multiple pipes, and planes are enabled after the pipe, we need to wait at
|
|
|
|
|
* least 2 vblanks on the first pipe before enabling planes on the second pipe.
|
|
|
|
|
*/
|
|
|
|
|
static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_crtc_state *crtc_state;
|
|
|
|
|
struct intel_crtc *intel_crtc;
|
|
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
struct intel_crtc_state *first_crtc_state = NULL;
|
|
|
|
|
struct intel_crtc_state *other_crtc_state = NULL;
|
|
|
|
|
enum pipe first_pipe = INVALID_PIPE, enabled_pipe = INVALID_PIPE;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* look at all crtc's that are going to be enabled in during modeset */
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
2015-06-01 12:50:09 +02:00
|
|
|
intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->active || !needs_modeset(crtc_state))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (first_crtc_state) {
|
|
|
|
|
other_crtc_state = to_intel_crtc_state(crtc_state);
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
first_crtc_state = to_intel_crtc_state(crtc_state);
|
|
|
|
|
first_pipe = intel_crtc->pipe;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No workaround needed? */
|
|
|
|
|
if (!first_crtc_state)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* w/a possibly needed, check how many crtc's are already enabled. */
|
|
|
|
|
for_each_intel_crtc(state->dev, intel_crtc) {
|
|
|
|
|
struct intel_crtc_state *pipe_config;
|
|
|
|
|
|
|
|
|
|
pipe_config = intel_atomic_get_crtc_state(state, intel_crtc);
|
|
|
|
|
if (IS_ERR(pipe_config))
|
|
|
|
|
return PTR_ERR(pipe_config);
|
|
|
|
|
|
|
|
|
|
pipe_config->hsw_workaround_pipe = INVALID_PIPE;
|
|
|
|
|
|
|
|
|
|
if (!pipe_config->base.active ||
|
|
|
|
|
needs_modeset(&pipe_config->base))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* 2 or more enabled crtcs means no need for w/a */
|
|
|
|
|
if (enabled_pipe != INVALID_PIPE)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
enabled_pipe = intel_crtc->pipe;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enabled_pipe != INVALID_PIPE)
|
|
|
|
|
first_crtc_state->hsw_workaround_pipe = enabled_pipe;
|
|
|
|
|
else if (other_crtc_state)
|
|
|
|
|
other_crtc_state->hsw_workaround_pipe = first_pipe;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 18:35:10 +02:00
|
|
|
static int intel_lock_all_pipes(struct drm_atomic_state *state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
|
|
|
|
|
/* Add all pipes to the state */
|
|
|
|
|
for_each_crtc(state->dev, crtc) {
|
|
|
|
|
struct drm_crtc_state *crtc_state;
|
|
|
|
|
|
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
|
|
|
if (IS_ERR(crtc_state))
|
|
|
|
|
return PTR_ERR(crtc_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 12:33:56 +02:00
|
|
|
static int intel_modeset_all_pipes(struct drm_atomic_state *state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
|
2016-11-14 18:35:10 +02:00
|
|
|
/*
|
|
|
|
|
* Add all pipes to the state, and force
|
|
|
|
|
* a modeset on all the active ones.
|
|
|
|
|
*/
|
2015-06-15 12:33:56 +02:00
|
|
|
for_each_crtc(state->dev, crtc) {
|
2016-11-14 18:35:11 +02:00
|
|
|
struct drm_crtc_state *crtc_state;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2015-06-15 12:33:56 +02:00
|
|
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
|
|
|
|
if (IS_ERR(crtc_state))
|
|
|
|
|
return PTR_ERR(crtc_state);
|
|
|
|
|
|
|
|
|
|
if (!crtc_state->active || needs_modeset(crtc_state))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
crtc_state->mode_changed = true;
|
|
|
|
|
|
|
|
|
|
ret = drm_atomic_add_affected_connectors(state, crtc);
|
|
|
|
|
if (ret)
|
2016-11-14 18:35:11 +02:00
|
|
|
return ret;
|
2015-06-15 12:33:56 +02:00
|
|
|
|
|
|
|
|
ret = drm_atomic_add_affected_planes(state, crtc);
|
|
|
|
|
if (ret)
|
2016-11-14 18:35:11 +02:00
|
|
|
return ret;
|
2015-06-15 12:33:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-14 18:35:11 +02:00
|
|
|
return 0;
|
2015-06-15 12:33:56 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-01 12:50:02 +02:00
|
|
|
static int intel_modeset_checks(struct drm_atomic_state *state)
|
2015-04-21 17:13:06 +03:00
|
|
|
{
|
2015-12-10 12:33:57 +01:00
|
|
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(state->dev);
|
2015-12-10 12:33:57 +01:00
|
|
|
struct drm_crtc *crtc;
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
2015-12-10 12:33:57 +01:00
|
|
|
int ret = 0, i;
|
2015-04-21 17:13:06 +03:00
|
|
|
|
2015-06-15 12:33:38 +02:00
|
|
|
if (!check_digital_port_conflicts(state)) {
|
|
|
|
|
DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-10 12:33:57 +01:00
|
|
|
intel_state->modeset = true;
|
|
|
|
|
intel_state->active_crtcs = dev_priv->active_crtcs;
|
2017-01-20 20:21:59 +02:00
|
|
|
intel_state->cdclk.logical = dev_priv->cdclk.logical;
|
|
|
|
|
intel_state->cdclk.actual = dev_priv->cdclk.actual;
|
2015-12-10 12:33:57 +01:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
|
|
|
|
if (new_crtc_state->active)
|
2015-12-10 12:33:57 +01:00
|
|
|
intel_state->active_crtcs |= 1 << i;
|
|
|
|
|
else
|
|
|
|
|
intel_state->active_crtcs &= ~(1 << i);
|
2016-05-12 07:06:00 -07:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
if (old_crtc_state->active != new_crtc_state->active)
|
2016-05-12 07:06:00 -07:00
|
|
|
intel_state->active_pipe_changes |= drm_crtc_mask(crtc);
|
2015-12-10 12:33:57 +01:00
|
|
|
}
|
|
|
|
|
|
2015-04-21 17:13:06 +03:00
|
|
|
/*
|
|
|
|
|
* See if the config requires any additional preparation, e.g.
|
|
|
|
|
* to adjust global state with pipes off. We need to do this
|
|
|
|
|
* here so we can get the modeset_pipe updated config for the new
|
|
|
|
|
* mode set on this crtc. For other crtcs we need to use the
|
|
|
|
|
* adjusted_mode bits in the crtc directly.
|
|
|
|
|
*/
|
2015-06-15 12:33:56 +02:00
|
|
|
if (dev_priv->display.modeset_calc_cdclk) {
|
|
|
|
|
ret = dev_priv->display.modeset_calc_cdclk(state);
|
2016-05-13 23:41:21 +03:00
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2015-06-15 12:33:56 +02:00
|
|
|
|
2016-11-14 18:35:10 +02:00
|
|
|
/*
|
2017-01-20 20:21:59 +02:00
|
|
|
* Writes to dev_priv->cdclk.logical must protected by
|
2016-11-14 18:35:10 +02:00
|
|
|
* holding all the crtc locks, even if we don't end up
|
|
|
|
|
* touching the hardware
|
|
|
|
|
*/
|
2017-10-24 12:52:08 +03:00
|
|
|
if (intel_cdclk_changed(&dev_priv->cdclk.logical,
|
|
|
|
|
&intel_state->cdclk.logical)) {
|
2016-11-14 18:35:10 +02:00
|
|
|
ret = intel_lock_all_pipes(state);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* All pipes must be switched off while we change the cdclk. */
|
2017-10-24 12:52:08 +03:00
|
|
|
if (intel_cdclk_needs_modeset(&dev_priv->cdclk.actual,
|
|
|
|
|
&intel_state->cdclk.actual)) {
|
2015-06-15 12:33:56 +02:00
|
|
|
ret = intel_modeset_all_pipes(state);
|
2016-11-14 18:35:10 +02:00
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2016-02-16 10:25:11 +01:00
|
|
|
|
2017-01-20 20:21:59 +02:00
|
|
|
DRM_DEBUG_KMS("New cdclk calculated to be logical %u kHz, actual %u kHz\n",
|
|
|
|
|
intel_state->cdclk.logical.cdclk,
|
|
|
|
|
intel_state->cdclk.actual.cdclk);
|
2017-10-24 12:52:14 +03:00
|
|
|
DRM_DEBUG_KMS("New voltage level calculated to be logical %u, actual %u\n",
|
|
|
|
|
intel_state->cdclk.logical.voltage_level,
|
|
|
|
|
intel_state->cdclk.actual.voltage_level);
|
2016-11-14 18:35:09 +02:00
|
|
|
} else {
|
2017-01-20 20:21:59 +02:00
|
|
|
to_intel_atomic_state(state)->cdclk.logical = dev_priv->cdclk.logical;
|
2016-11-14 18:35:09 +02:00
|
|
|
}
|
2015-04-21 17:13:06 +03:00
|
|
|
|
2015-06-15 12:33:42 +02:00
|
|
|
intel_modeset_clear_plls(state);
|
2015-04-21 17:13:06 +03:00
|
|
|
|
2015-12-10 12:33:57 +01:00
|
|
|
if (IS_HASWELL(dev_priv))
|
2015-06-15 12:33:42 +02:00
|
|
|
return haswell_mode_set_planes_workaround(state);
|
2015-06-01 12:50:09 +02:00
|
|
|
|
2015-06-15 12:33:42 +02:00
|
|
|
return 0;
|
2015-06-01 12:50:02 +02:00
|
|
|
}
|
|
|
|
|
|
2015-09-24 15:53:18 -07:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2016-05-12 07:06:08 -07:00
|
|
|
static int calc_watermark_data(struct drm_atomic_state *state)
|
2015-09-24 15:53:18 -07:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = state->dev;
|
2016-05-12 07:06:03 -07:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
|
|
|
|
|
/* Is there platform-specific watermark information to calculate? */
|
|
|
|
|
if (dev_priv->display.compute_global_watermarks)
|
2016-05-12 07:06:08 -07:00
|
|
|
return dev_priv->display.compute_global_watermarks(state);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2015-09-24 15:53:18 -07:00
|
|
|
}
|
|
|
|
|
|
2015-07-13 16:30:30 +02:00
|
|
|
/**
|
|
|
|
|
* intel_atomic_check - validate state object
|
|
|
|
|
* @dev: drm device
|
|
|
|
|
* @state: state to validate
|
|
|
|
|
*/
|
|
|
|
|
static int intel_atomic_check(struct drm_device *dev,
|
|
|
|
|
struct drm_atomic_state *state)
|
2015-06-01 12:50:02 +02:00
|
|
|
{
|
2016-01-19 11:35:49 -02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-09-24 15:53:18 -07:00
|
|
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
2015-06-01 12:50:02 +02:00
|
|
|
struct drm_crtc *crtc;
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_crtc_state *old_crtc_state, *crtc_state;
|
2015-06-01 12:50:02 +02:00
|
|
|
int ret, i;
|
2015-06-15 12:33:50 +02:00
|
|
|
bool any_ms = false;
|
2015-06-01 12:50:02 +02:00
|
|
|
|
2015-07-13 16:30:30 +02:00
|
|
|
ret = drm_atomic_helper_check_modeset(dev, state);
|
2015-04-21 17:13:06 +03:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) {
|
2015-07-14 12:17:40 +02:00
|
|
|
struct intel_crtc_state *pipe_config =
|
|
|
|
|
to_intel_crtc_state(crtc_state);
|
2015-07-15 14:15:51 +02:00
|
|
|
|
|
|
|
|
/* Catch I915_MODE_FLAG_INHERITED */
|
2017-03-09 15:52:04 +01:00
|
|
|
if (crtc_state->mode.private_flags != old_crtc_state->mode.private_flags)
|
2015-07-15 14:15:51 +02:00
|
|
|
crtc_state->mode_changed = true;
|
2015-07-14 12:17:40 +02:00
|
|
|
|
2016-05-09 09:31:25 +02:00
|
|
|
if (!needs_modeset(crtc_state))
|
2015-06-01 12:50:02 +02:00
|
|
|
continue;
|
|
|
|
|
|
2016-05-09 09:31:25 +02:00
|
|
|
if (!crtc_state->enable) {
|
|
|
|
|
any_ms = true;
|
2015-07-14 12:17:40 +02:00
|
|
|
continue;
|
2016-05-09 09:31:25 +02:00
|
|
|
}
|
2015-07-14 12:17:40 +02:00
|
|
|
|
2015-07-15 14:15:52 +02:00
|
|
|
/* FIXME: For only active_changed we shouldn't need to do any
|
|
|
|
|
* state recomputation at all. */
|
|
|
|
|
|
2015-07-15 14:15:51 +02:00
|
|
|
ret = drm_atomic_add_affected_connectors(state, crtc);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2015-06-15 12:33:38 +02:00
|
|
|
|
2015-07-14 12:17:40 +02:00
|
|
|
ret = intel_modeset_pipe_config(crtc, pipe_config);
|
2016-05-03 10:30:38 +02:00
|
|
|
if (ret) {
|
|
|
|
|
intel_dump_pipe_config(to_intel_crtc(crtc),
|
|
|
|
|
pipe_config, "[failed]");
|
2015-06-01 12:50:02 +02:00
|
|
|
return ret;
|
2016-05-03 10:30:38 +02:00
|
|
|
}
|
2015-06-01 12:50:02 +02:00
|
|
|
|
2017-09-19 19:38:44 +00:00
|
|
|
if (i915_modparams.fastboot &&
|
2016-11-16 12:32:42 +00:00
|
|
|
intel_pipe_config_compare(dev_priv,
|
2017-03-09 15:52:04 +01:00
|
|
|
to_intel_crtc_state(old_crtc_state),
|
2015-07-15 14:15:51 +02:00
|
|
|
pipe_config, true)) {
|
2015-07-15 14:15:52 +02:00
|
|
|
crtc_state->mode_changed = false;
|
2017-03-09 15:52:04 +01:00
|
|
|
pipe_config->update_pipe = true;
|
2015-07-15 14:15:52 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-09 09:31:25 +02:00
|
|
|
if (needs_modeset(crtc_state))
|
2015-07-15 14:15:52 +02:00
|
|
|
any_ms = true;
|
2015-07-14 12:17:40 +02:00
|
|
|
|
2016-05-09 09:31:25 +02:00
|
|
|
ret = drm_atomic_add_affected_planes(state, crtc);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2015-06-15 12:33:50 +02:00
|
|
|
|
2015-07-15 14:15:52 +02:00
|
|
|
intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
|
|
|
|
|
needs_modeset(crtc_state) ?
|
|
|
|
|
"[modeset]" : "[fastset]");
|
2015-06-01 12:50:02 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-15 12:33:50 +02:00
|
|
|
if (any_ms) {
|
|
|
|
|
ret = intel_modeset_checks(state);
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2016-11-14 18:35:09 +02:00
|
|
|
} else {
|
2017-01-20 20:21:59 +02:00
|
|
|
intel_state->cdclk.logical = dev_priv->cdclk.logical;
|
2016-11-14 18:35:09 +02:00
|
|
|
}
|
2015-09-24 15:53:18 -07:00
|
|
|
|
2016-01-19 11:35:49 -02:00
|
|
|
ret = drm_atomic_helper_check_planes(dev, state);
|
2015-09-24 15:53:18 -07:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2017-11-17 21:19:14 +02:00
|
|
|
intel_fbc_choose_crtc(dev_priv, intel_state);
|
2016-05-12 07:06:08 -07:00
|
|
|
return calc_watermark_data(state);
|
2015-04-21 17:13:06 +03:00
|
|
|
}
|
|
|
|
|
|
2015-08-18 13:40:05 +02:00
|
|
|
static int intel_atomic_prepare_commit(struct drm_device *dev,
|
drm/i915: Move GEM activity tracking into a common struct reservation_object
In preparation to support many distinct timelines, we need to expand the
activity tracking on the GEM object to handle more than just a request
per engine. We already use the struct reservation_object on the dma-buf
to handle many fence contexts, so integrating that into the GEM object
itself is the preferred solution. (For example, we can now share the same
reservation_object between every consumer/producer using this buffer and
skip the manual import/export via dma-buf.)
v2: Reimplement busy-ioctl (by walking the reservation object), postpone
the ABI change for another day. Similarly use the reservation object to
find the last_write request (if active and from i915) for choosing
display CS flips.
Caveats:
* busy-ioctl: busy-ioctl only reports on the native fences, it will not
warn of stalls (in set-domain-ioctl, pread/pwrite etc) if the object is
being rendered to by external fences. It also will not report the same
busy state as wait-ioctl (or polling on the dma-buf) in the same
circumstances. On the plus side, it does retain reporting of which
*i915* engines are engaged with this object.
* non-blocking atomic modesets take a step backwards as the wait for
render completion blocks the ioctl. This is fixed in a subsequent
patch to use a fence instead for awaiting on the rendering, see
"drm/i915: Restore nonblocking awaits for modesetting"
* dynamic array manipulation for shared-fences in reservation is slower
than the previous lockless static assignment (e.g. gem_exec_lut_handle
runtime on ivb goes from 42s to 66s), mainly due to atomic operations
(maintaining the fence refcounts).
* loss of object-level retirement callbacks, emulated by VMA retirement
tracking.
* minor loss of object-level last activity information from debugfs,
could be replaced with per-vma information if desired
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161028125858.23563-21-chris@chris-wilson.co.uk
2016-10-28 13:58:44 +01:00
|
|
|
struct drm_atomic_state *state)
|
2015-08-18 13:40:05 +02:00
|
|
|
{
|
2017-07-26 17:00:36 +01:00
|
|
|
return drm_atomic_helper_prepare_planes(dev, state);
|
2015-08-18 13:40:05 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-17 15:07:48 +02:00
|
|
|
u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
|
|
|
|
|
|
|
|
|
if (!dev->max_vblank_count)
|
2017-05-24 16:51:47 +02:00
|
|
|
return drm_crtc_accurate_vblank_count(&crtc->base);
|
2016-05-17 15:07:48 +02:00
|
|
|
|
|
|
|
|
return dev->driver->get_vblank_counter(dev, crtc->pipe);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-24 07:48:09 +02:00
|
|
|
static void intel_update_crtc(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_atomic_state *state,
|
|
|
|
|
struct drm_crtc_state *old_crtc_state,
|
2017-09-04 12:48:33 +02:00
|
|
|
struct drm_crtc_state *new_crtc_state)
|
2016-08-24 07:48:09 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2017-03-09 15:52:04 +01:00
|
|
|
struct intel_crtc_state *pipe_config = to_intel_crtc_state(new_crtc_state);
|
|
|
|
|
bool modeset = needs_modeset(new_crtc_state);
|
2016-08-24 07:48:09 +02:00
|
|
|
|
|
|
|
|
if (modeset) {
|
|
|
|
|
update_scanline_offset(intel_crtc);
|
|
|
|
|
dev_priv->display.crtc_enable(pipe_config, state);
|
|
|
|
|
} else {
|
2017-03-09 15:52:04 +01:00
|
|
|
intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
|
|
|
|
|
pipe_config);
|
2016-08-24 07:48:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
|
|
|
|
|
intel_fbc_enable(
|
|
|
|
|
intel_crtc, pipe_config,
|
|
|
|
|
to_intel_plane_state(crtc->primary->state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-04 12:48:33 +02:00
|
|
|
static void intel_update_crtcs(struct drm_atomic_state *state)
|
2016-08-24 07:48:09 +02:00
|
|
|
{
|
|
|
|
|
struct drm_crtc *crtc;
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
2016-08-24 07:48:09 +02:00
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
|
|
|
|
if (!new_crtc_state->active)
|
2016-08-24 07:48:09 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
intel_update_crtc(crtc, state, old_crtc_state,
|
2017-09-04 12:48:33 +02:00
|
|
|
new_crtc_state);
|
2016-08-24 07:48:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-04 12:48:33 +02:00
|
|
|
static void skl_update_crtcs(struct drm_atomic_state *state)
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
{
|
2016-10-31 22:37:06 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(state->dev);
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
|
|
|
|
struct drm_crtc *crtc;
|
2016-09-15 10:46:35 -04:00
|
|
|
struct intel_crtc *intel_crtc;
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
2016-09-15 10:46:35 -04:00
|
|
|
struct intel_crtc_state *cstate;
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
unsigned int updated = 0;
|
|
|
|
|
bool progress;
|
|
|
|
|
enum pipe pipe;
|
2016-11-08 13:55:35 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
const struct skl_ddb_entry *entries[I915_MAX_PIPES] = {};
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i)
|
2016-11-08 13:55:35 +01:00
|
|
|
/* ignore allocations for crtc's that have been turned off. */
|
2017-03-09 15:52:04 +01:00
|
|
|
if (new_crtc_state->active)
|
2016-11-08 13:55:35 +01:00
|
|
|
entries[i] = &to_intel_crtc_state(old_crtc_state)->wm.skl.ddb;
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Whenever the number of active pipes changes, we need to make sure we
|
|
|
|
|
* update the pipes in the right order so that their ddb allocations
|
|
|
|
|
* never overlap with eachother inbetween CRTC updates. Otherwise we'll
|
|
|
|
|
* cause pipe underruns and other bad stuff.
|
|
|
|
|
*/
|
|
|
|
|
do {
|
|
|
|
|
progress = false;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
bool vbl_wait = false;
|
|
|
|
|
unsigned int cmask = drm_crtc_mask(crtc);
|
2016-09-15 10:46:35 -04:00
|
|
|
|
|
|
|
|
intel_crtc = to_intel_crtc(crtc);
|
2017-08-23 18:22:26 +03:00
|
|
|
cstate = to_intel_crtc_state(new_crtc_state);
|
2016-09-15 10:46:35 -04:00
|
|
|
pipe = intel_crtc->pipe;
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
|
2016-11-08 13:55:35 +01:00
|
|
|
if (updated & cmask || !cstate->base.active)
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
continue;
|
2016-11-08 13:55:35 +01:00
|
|
|
|
2017-10-10 13:17:03 +03:00
|
|
|
if (skl_ddb_allocation_overlaps(dev_priv,
|
|
|
|
|
entries,
|
|
|
|
|
&cstate->wm.skl.ddb,
|
|
|
|
|
i))
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
updated |= cmask;
|
2016-11-08 13:55:35 +01:00
|
|
|
entries[i] = &cstate->wm.skl.ddb;
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If this is an already active pipe, it's DDB changed,
|
|
|
|
|
* and this isn't the last pipe that needs updating
|
|
|
|
|
* then we need to wait for a vblank to pass for the
|
|
|
|
|
* new ddb allocation to take effect.
|
|
|
|
|
*/
|
2016-09-15 10:46:35 -04:00
|
|
|
if (!skl_ddb_entry_equal(&cstate->wm.skl.ddb,
|
2016-11-08 13:55:34 +01:00
|
|
|
&to_intel_crtc_state(old_crtc_state)->wm.skl.ddb) &&
|
2017-03-09 15:52:04 +01:00
|
|
|
!new_crtc_state->active_changed &&
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
intel_state->wm_results.dirty_pipes != updated)
|
|
|
|
|
vbl_wait = true;
|
|
|
|
|
|
|
|
|
|
intel_update_crtc(crtc, state, old_crtc_state,
|
2017-09-04 12:48:33 +02:00
|
|
|
new_crtc_state);
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
|
|
|
|
|
if (vbl_wait)
|
2016-10-31 22:37:06 +02:00
|
|
|
intel_wait_for_vblank(dev_priv, pipe);
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
|
|
|
|
|
progress = true;
|
|
|
|
|
}
|
|
|
|
|
} while (progress);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-02 20:47:41 +00:00
|
|
|
static void intel_atomic_helper_free_state(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
struct intel_atomic_state *state, *next;
|
|
|
|
|
struct llist_node *freed;
|
|
|
|
|
|
|
|
|
|
freed = llist_del_all(&dev_priv->atomic_helper.free_list);
|
|
|
|
|
llist_for_each_entry_safe(state, next, freed, freed)
|
|
|
|
|
drm_atomic_state_put(&state->base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_atomic_helper_free_state_worker(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv =
|
|
|
|
|
container_of(work, typeof(*dev_priv), atomic_helper.free_work);
|
|
|
|
|
|
|
|
|
|
intel_atomic_helper_free_state(dev_priv);
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: More surgically unbreak the modeset vs reset deadlock
There's no reason to entirely wedge the gpu, for the minimal deadlock
bugfix we only need to unbreak/decouple the atomic commit from the gpu
reset. The simplest way to fix that is by replacing the
unconditional fence wait a the top of commit_tail by a wait which
completes either when the fences are done (normal case, or when a
reset doesn't need to touch the display state). Or when the gpu reset
needs to force-unblock all pending modeset states.
The lesser source of deadlocks is when we try to pin a new framebuffer
and run into a stall. There's a bunch of places this can happen, like
eviction, changing the caching mode, acquiring a fence on older
platforms. And we can't just break the depency loop and keep going,
the only way would be to break out and restart. But the problem with
that approach is that we must stall for the reset to complete before
we grab any locks, and with the atomic infrastructure that's a bit
tricky. The only place is the ioctl code, and we don't want to insert
code into e.g. the BUSY ioctl. Hence for that problem just create a
critical section, and if any code is in there, wedge the GPU. For the
steady-state this should never be a problem.
Note that in both cases TDR itself keeps working, so from a userspace
pov this trickery isn't observable. Users themselvs might spot a short
glitch while the rendering is catching up again, but that's still
better than pre-TDR where we've thrown away all the rendering,
including innocent batches. Also, this fixes the regression TDR
introduced of making gpu resets deadlock-prone when we do need to
touch the display.
One thing I noticed is that gpu_error.flags seems to use both our own
wait-queue in gpu_error.wait_queue, and the generic wait_on_bit
facilities. Not entirely sure why this inconsistency exists, I just
picked one style.
A possible future avenue could be to insert the gpu reset in-between
ongoing modeset changes, which would avoid the momentary glitch. But
that's a lot more work to implement in the atomic commit machinery,
and given that we only need this for pre-g4x hw, of questionable
utility just for the sake of polishing gpu reset even more on those
old boxes. It might be useful for other features though.
v2: Rebase onto 4.13 with a s/wait_queue_t/struct wait_queue_entry/.
v3: Really emabarrassing fixup, I checked the wrong bit and broke the
unbreak/wakeup logic.
v4: Also handle deadlocks in pin_to_display.
v5: Review from Michel:
- Fixup the BUILD_BUG_ON
- Don't forget about the overlay
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v2)
Cc: Michel Thierry <michel.thierry@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170808080828.23650-3-daniel.vetter@ffwll.ch
Reviewed-by: Michel Thierry <michel.thierry@intel.com>
2017-08-08 10:08:28 +02:00
|
|
|
static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_state)
|
|
|
|
|
{
|
|
|
|
|
struct wait_queue_entry wait_fence, wait_reset;
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(intel_state->base.dev);
|
|
|
|
|
|
|
|
|
|
init_wait_entry(&wait_fence, 0);
|
|
|
|
|
init_wait_entry(&wait_reset, 0);
|
|
|
|
|
for (;;) {
|
|
|
|
|
prepare_to_wait(&intel_state->commit_ready.wait,
|
|
|
|
|
&wait_fence, TASK_UNINTERRUPTIBLE);
|
|
|
|
|
prepare_to_wait(&dev_priv->gpu_error.wait_queue,
|
|
|
|
|
&wait_reset, TASK_UNINTERRUPTIBLE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i915_sw_fence_done(&intel_state->commit_ready)
|
|
|
|
|
|| test_bit(I915_RESET_MODESET, &dev_priv->gpu_error.flags))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
schedule();
|
|
|
|
|
}
|
|
|
|
|
finish_wait(&intel_state->commit_ready.wait, &wait_fence);
|
|
|
|
|
finish_wait(&dev_priv->gpu_error.wait_queue, &wait_reset);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-14 18:01:00 +02:00
|
|
|
static void intel_atomic_commit_tail(struct drm_atomic_state *state)
|
2012-07-02 09:56:42 +02:00
|
|
|
{
|
2016-06-14 18:01:00 +02:00
|
|
|
struct drm_device *dev = state->dev;
|
2015-12-10 12:33:57 +01:00
|
|
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
2015-08-18 13:40:06 +02:00
|
|
|
struct drm_crtc *crtc;
|
2016-05-24 17:13:53 +02:00
|
|
|
struct intel_crtc_state *intel_cstate;
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 put_domains[I915_MAX_PIPES] = {};
|
2016-10-28 13:58:27 +01:00
|
|
|
int i;
|
2012-07-02 09:56:42 +02:00
|
|
|
|
drm/i915: More surgically unbreak the modeset vs reset deadlock
There's no reason to entirely wedge the gpu, for the minimal deadlock
bugfix we only need to unbreak/decouple the atomic commit from the gpu
reset. The simplest way to fix that is by replacing the
unconditional fence wait a the top of commit_tail by a wait which
completes either when the fences are done (normal case, or when a
reset doesn't need to touch the display state). Or when the gpu reset
needs to force-unblock all pending modeset states.
The lesser source of deadlocks is when we try to pin a new framebuffer
and run into a stall. There's a bunch of places this can happen, like
eviction, changing the caching mode, acquiring a fence on older
platforms. And we can't just break the depency loop and keep going,
the only way would be to break out and restart. But the problem with
that approach is that we must stall for the reset to complete before
we grab any locks, and with the atomic infrastructure that's a bit
tricky. The only place is the ioctl code, and we don't want to insert
code into e.g. the BUSY ioctl. Hence for that problem just create a
critical section, and if any code is in there, wedge the GPU. For the
steady-state this should never be a problem.
Note that in both cases TDR itself keeps working, so from a userspace
pov this trickery isn't observable. Users themselvs might spot a short
glitch while the rendering is catching up again, but that's still
better than pre-TDR where we've thrown away all the rendering,
including innocent batches. Also, this fixes the regression TDR
introduced of making gpu resets deadlock-prone when we do need to
touch the display.
One thing I noticed is that gpu_error.flags seems to use both our own
wait-queue in gpu_error.wait_queue, and the generic wait_on_bit
facilities. Not entirely sure why this inconsistency exists, I just
picked one style.
A possible future avenue could be to insert the gpu reset in-between
ongoing modeset changes, which would avoid the momentary glitch. But
that's a lot more work to implement in the atomic commit machinery,
and given that we only need this for pre-g4x hw, of questionable
utility just for the sake of polishing gpu reset even more on those
old boxes. It might be useful for other features though.
v2: Rebase onto 4.13 with a s/wait_queue_t/struct wait_queue_entry/.
v3: Really emabarrassing fixup, I checked the wrong bit and broke the
unbreak/wakeup logic.
v4: Also handle deadlocks in pin_to_display.
v5: Review from Michel:
- Fixup the BUILD_BUG_ON
- Don't forget about the overlay
Cc: Michel Thierry <michel.thierry@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v2)
Cc: Michel Thierry <michel.thierry@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170808080828.23650-3-daniel.vetter@ffwll.ch
Reviewed-by: Michel Thierry <michel.thierry@intel.com>
2017-08-08 10:08:28 +02:00
|
|
|
intel_atomic_commit_fence_wait(intel_state);
|
2017-08-08 10:08:27 +02:00
|
|
|
|
2016-06-13 16:13:46 +02:00
|
|
|
drm_atomic_helper_wait_for_dependencies(state);
|
|
|
|
|
|
2016-11-08 13:55:40 +01:00
|
|
|
if (intel_state->modeset)
|
2016-05-24 17:13:53 +02:00
|
|
|
intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
|
2015-12-10 12:33:57 +01:00
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
2015-06-15 12:33:52 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
if (needs_modeset(new_crtc_state) ||
|
|
|
|
|
to_intel_crtc_state(new_crtc_state)->update_pipe) {
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
put_domains[to_intel_crtc(crtc)->pipe] =
|
|
|
|
|
modeset_get_crtc_power_domains(crtc,
|
2017-03-09 15:52:04 +01:00
|
|
|
to_intel_crtc_state(new_crtc_state));
|
2016-05-24 17:13:53 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
if (!needs_modeset(new_crtc_state))
|
2015-06-15 12:33:50 +02:00
|
|
|
continue;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
intel_pre_plane_update(to_intel_crtc_state(old_crtc_state),
|
|
|
|
|
to_intel_crtc_state(new_crtc_state));
|
2013-03-27 00:44:51 +01:00
|
|
|
|
2016-03-09 19:07:27 +02:00
|
|
|
if (old_crtc_state->active) {
|
|
|
|
|
intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
|
2016-08-09 17:04:01 +02:00
|
|
|
dev_priv->display.crtc_disable(to_intel_crtc_state(old_crtc_state), state);
|
2015-06-15 12:33:53 +02:00
|
|
|
intel_crtc->active = false;
|
2016-01-19 11:35:51 -02:00
|
|
|
intel_fbc_disable(intel_crtc);
|
2015-06-15 12:33:53 +02:00
|
|
|
intel_disable_shared_dpll(intel_crtc);
|
2015-11-20 22:09:20 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Underruns don't always raise
|
|
|
|
|
* interrupts, so check manually.
|
|
|
|
|
*/
|
|
|
|
|
intel_check_cpu_fifo_underruns(dev_priv);
|
|
|
|
|
intel_check_pch_fifo_underruns(dev_priv);
|
2015-11-19 16:07:16 +01:00
|
|
|
|
2017-08-23 18:22:26 +03:00
|
|
|
if (!new_crtc_state->active) {
|
2016-11-08 13:55:33 +01:00
|
|
|
/*
|
|
|
|
|
* Make sure we don't call initial_watermarks
|
|
|
|
|
* for ILK-style watermark updates.
|
2017-03-02 19:14:57 +02:00
|
|
|
*
|
|
|
|
|
* No clue what this is supposed to achieve.
|
2016-11-08 13:55:33 +01:00
|
|
|
*/
|
2017-03-02 19:14:57 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2016-11-08 13:55:33 +01:00
|
|
|
dev_priv->display.initial_watermarks(intel_state,
|
2017-08-23 18:22:26 +03:00
|
|
|
to_intel_crtc_state(new_crtc_state));
|
2016-11-08 13:55:33 +01:00
|
|
|
}
|
2015-06-15 12:33:52 +02:00
|
|
|
}
|
2013-03-27 00:44:50 +01:00
|
|
|
}
|
2012-07-08 19:40:39 +02:00
|
|
|
|
2017-12-07 15:32:02 +01:00
|
|
|
/* FIXME: Eventually get rid of our intel_crtc->config pointer */
|
|
|
|
|
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
|
|
|
|
|
to_intel_crtc(crtc)->config = to_intel_crtc_state(new_crtc_state);
|
2011-04-12 18:06:51 +01:00
|
|
|
|
2015-12-10 12:33:57 +01:00
|
|
|
if (intel_state->modeset) {
|
2015-08-05 12:37:10 +02:00
|
|
|
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
|
2016-02-10 13:49:37 +01:00
|
|
|
|
2017-01-26 21:52:01 +02:00
|
|
|
intel_set_cdclk(dev_priv, &dev_priv->cdclk.actual);
|
2016-03-23 14:58:07 +01:00
|
|
|
|
drm/i915/skl: Add support for the SAGV, fix underrun hangs
Since the watermark calculations for Skylake are still broken, we're apt
to hitting underruns very easily under multi-monitor configurations.
While it would be lovely if this was fixed, it's not. Another problem
that's been coming from this however, is the mysterious issue of
underruns causing full system hangs. An easy way to reproduce this with
a skylake system:
- Get a laptop with a skylake GPU, and hook up two external monitors to
it
- Move the cursor from the built-in LCD to one of the external displays
as quickly as you can
- You'll get a few pipe underruns, and eventually the entire system will
just freeze.
After doing a lot of investigation and reading through the bspec, I
found the existence of the SAGV, which is responsible for adjusting the
system agent voltage and clock frequencies depending on how much power
we need. According to the bspec:
"The display engine access to system memory is blocked during the
adjustment time. SAGV defaults to enabled. Software must use the
GT-driver pcode mailbox to disable SAGV when the display engine is not
able to tolerate the blocking time."
The rest of the bspec goes on to explain that software can simply leave
the SAGV enabled, and disable it when we use interlaced pipes/have more
then one pipe active.
Sure enough, with this patchset the system hangs resulting from pipe
underruns on Skylake have completely vanished on my T460s. Additionally,
the bspec mentions turning off the SAGV with more then one pipe enabled
as a workaround for display underruns. While this patch doesn't entirely
fix that, it looks like it does improve the situation a little bit so
it's likely this is going to be required to make watermarks on Skylake
fully functional.
This will still need additional work in the future: we shouldn't be
enabling the SAGV if any of the currently enabled planes can't enable WM
levels that introduce latencies >= 30 µs.
Changes since v11:
- Add skl_can_enable_sagv()
- Make sure we don't enable SAGV when not all planes can enable
watermarks >= the SAGV engine block time. I was originally going to
save this for later, but I recently managed to run into a machine
that was having problems with a single pipe configuration + SAGV.
- Make comparisons to I915_SKL_SAGV_NOT_CONTROLLED explicit
- Change I915_SAGV_DYNAMIC_FREQ to I915_SAGV_ENABLE
- Move printks outside of mutexes
- Don't print error messages twice
Changes since v10:
- Apparently sandybridge_pcode_read actually writes values and reads
them back, despite it's misleading function name. This means we've
been doing this mostly wrong and have been writing garbage to the
SAGV control. Because of this, we no longer attempt to read the SAGV
status during initialization (since there are no helpers for this).
- mlankhorst noticed that this patch was breaking on some very early
pre-release Skylake machines, which apparently don't allow you to
disable the SAGV. To prevent machines from failing tests due to SAGV
errors, if the first time we try to control the SAGV results in the
mailbox indicating an invalid command, we just disable future attempts
to control the SAGV state by setting dev_priv->skl_sagv_status to
I915_SKL_SAGV_NOT_CONTROLLED and make a note of it in dmesg.
- Move mutex_unlock() a little higher in skl_enable_sagv(). This
doesn't actually fix anything, but lets us release the lock a little
sooner since we're finished with it.
Changes since v9:
- Only enable/disable sagv on Skylake
Changes since v8:
- Add intel_state->modeset guard to the conditional for
skl_enable_sagv()
Changes since v7:
- Remove GEN9_SAGV_LOW_FREQ, replace with GEN9_SAGV_IS_ENABLED (that's
all we use it for anyway)
- Use GEN9_SAGV_IS_ENABLED instead of 0x1 for clarification
- Fix a styling error that snuck past me
Changes since v6:
- Protect skl_enable_sagv() with intel_state->modeset conditional in
intel_atomic_commit_tail()
Changes since v5:
- Don't use is_power_of_2. Makes things confusing
- Don't use the old state to figure out whether or not to
enable/disable the sagv, use the new one
- Split the loop in skl_disable_sagv into it's own function
- Move skl_sagv_enable/disable() calls into intel_atomic_commit_tail()
Changes since v4:
- Use is_power_of_2 against active_crtcs to check whether we have > 1
pipe enabled
- Fix skl_sagv_get_hw_state(): (temp & 0x1) indicates disabled, 0x0
enabled
- Call skl_sagv_enable/disable() from pre/post-plane updates
Changes since v3:
- Use time_before() to compare timeout to jiffies
Changes since v2:
- Really apply minor style nitpicks to patch this time
Changes since v1:
- Added comments about this probably being one of the requirements to
fixing Skylake's watermark issues
- Minor style nitpicks from Matt Roper
- Disable these functions on Broxton, since it doesn't have an SAGV
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471463761-26796-3-git-send-email-cpaul@redhat.com
[mlankhorst: ENOSYS -> ENXIO, whitespace fixes]
2016-08-17 15:55:54 -04:00
|
|
|
/*
|
|
|
|
|
* SKL workaround: bspec recommends we disable the SAGV when we
|
|
|
|
|
* have more then one pipe enabled
|
|
|
|
|
*/
|
2016-09-22 18:00:28 -03:00
|
|
|
if (!intel_can_enable_sagv(state))
|
2016-09-22 18:00:27 -03:00
|
|
|
intel_disable_sagv(dev_priv);
|
drm/i915/skl: Add support for the SAGV, fix underrun hangs
Since the watermark calculations for Skylake are still broken, we're apt
to hitting underruns very easily under multi-monitor configurations.
While it would be lovely if this was fixed, it's not. Another problem
that's been coming from this however, is the mysterious issue of
underruns causing full system hangs. An easy way to reproduce this with
a skylake system:
- Get a laptop with a skylake GPU, and hook up two external monitors to
it
- Move the cursor from the built-in LCD to one of the external displays
as quickly as you can
- You'll get a few pipe underruns, and eventually the entire system will
just freeze.
After doing a lot of investigation and reading through the bspec, I
found the existence of the SAGV, which is responsible for adjusting the
system agent voltage and clock frequencies depending on how much power
we need. According to the bspec:
"The display engine access to system memory is blocked during the
adjustment time. SAGV defaults to enabled. Software must use the
GT-driver pcode mailbox to disable SAGV when the display engine is not
able to tolerate the blocking time."
The rest of the bspec goes on to explain that software can simply leave
the SAGV enabled, and disable it when we use interlaced pipes/have more
then one pipe active.
Sure enough, with this patchset the system hangs resulting from pipe
underruns on Skylake have completely vanished on my T460s. Additionally,
the bspec mentions turning off the SAGV with more then one pipe enabled
as a workaround for display underruns. While this patch doesn't entirely
fix that, it looks like it does improve the situation a little bit so
it's likely this is going to be required to make watermarks on Skylake
fully functional.
This will still need additional work in the future: we shouldn't be
enabling the SAGV if any of the currently enabled planes can't enable WM
levels that introduce latencies >= 30 µs.
Changes since v11:
- Add skl_can_enable_sagv()
- Make sure we don't enable SAGV when not all planes can enable
watermarks >= the SAGV engine block time. I was originally going to
save this for later, but I recently managed to run into a machine
that was having problems with a single pipe configuration + SAGV.
- Make comparisons to I915_SKL_SAGV_NOT_CONTROLLED explicit
- Change I915_SAGV_DYNAMIC_FREQ to I915_SAGV_ENABLE
- Move printks outside of mutexes
- Don't print error messages twice
Changes since v10:
- Apparently sandybridge_pcode_read actually writes values and reads
them back, despite it's misleading function name. This means we've
been doing this mostly wrong and have been writing garbage to the
SAGV control. Because of this, we no longer attempt to read the SAGV
status during initialization (since there are no helpers for this).
- mlankhorst noticed that this patch was breaking on some very early
pre-release Skylake machines, which apparently don't allow you to
disable the SAGV. To prevent machines from failing tests due to SAGV
errors, if the first time we try to control the SAGV results in the
mailbox indicating an invalid command, we just disable future attempts
to control the SAGV state by setting dev_priv->skl_sagv_status to
I915_SKL_SAGV_NOT_CONTROLLED and make a note of it in dmesg.
- Move mutex_unlock() a little higher in skl_enable_sagv(). This
doesn't actually fix anything, but lets us release the lock a little
sooner since we're finished with it.
Changes since v9:
- Only enable/disable sagv on Skylake
Changes since v8:
- Add intel_state->modeset guard to the conditional for
skl_enable_sagv()
Changes since v7:
- Remove GEN9_SAGV_LOW_FREQ, replace with GEN9_SAGV_IS_ENABLED (that's
all we use it for anyway)
- Use GEN9_SAGV_IS_ENABLED instead of 0x1 for clarification
- Fix a styling error that snuck past me
Changes since v6:
- Protect skl_enable_sagv() with intel_state->modeset conditional in
intel_atomic_commit_tail()
Changes since v5:
- Don't use is_power_of_2. Makes things confusing
- Don't use the old state to figure out whether or not to
enable/disable the sagv, use the new one
- Split the loop in skl_disable_sagv into it's own function
- Move skl_sagv_enable/disable() calls into intel_atomic_commit_tail()
Changes since v4:
- Use is_power_of_2 against active_crtcs to check whether we have > 1
pipe enabled
- Fix skl_sagv_get_hw_state(): (temp & 0x1) indicates disabled, 0x0
enabled
- Call skl_sagv_enable/disable() from pre/post-plane updates
Changes since v3:
- Use time_before() to compare timeout to jiffies
Changes since v2:
- Really apply minor style nitpicks to patch this time
Changes since v1:
- Added comments about this probably being one of the requirements to
fixing Skylake's watermark issues
- Minor style nitpicks from Matt Roper
- Disable these functions on Broxton, since it doesn't have an SAGV
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471463761-26796-3-git-send-email-cpaul@redhat.com
[mlankhorst: ENOSYS -> ENXIO, whitespace fixes]
2016-08-17 15:55:54 -04:00
|
|
|
|
2016-11-08 13:55:41 +01:00
|
|
|
intel_modeset_verify_disabled(dev, state);
|
2015-08-05 12:37:10 +02:00
|
|
|
}
|
2012-10-26 10:58:18 +02:00
|
|
|
|
2016-08-24 07:48:09 +02:00
|
|
|
/* Complete the events for pipes that have now been disabled */
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
|
|
|
|
|
bool modeset = needs_modeset(new_crtc_state);
|
2014-05-15 20:23:23 +03:00
|
|
|
|
2016-06-13 16:13:45 +02:00
|
|
|
/* Complete events for now disable pipes here. */
|
2017-03-09 15:52:04 +01:00
|
|
|
if (modeset && !new_crtc_state->active && new_crtc_state->event) {
|
2016-06-13 16:13:45 +02:00
|
|
|
spin_lock_irq(&dev->event_lock);
|
2017-03-09 15:52:04 +01:00
|
|
|
drm_crtc_send_vblank_event(crtc, new_crtc_state->event);
|
2016-06-13 16:13:45 +02:00
|
|
|
spin_unlock_irq(&dev->event_lock);
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
new_crtc_state->event = NULL;
|
2016-06-13 16:13:45 +02:00
|
|
|
}
|
2016-03-04 15:59:39 -08:00
|
|
|
}
|
|
|
|
|
|
2016-08-24 07:48:09 +02:00
|
|
|
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
|
2017-09-04 12:48:33 +02:00
|
|
|
dev_priv->display.update_crtcs(state);
|
2016-08-24 07:48:09 +02:00
|
|
|
|
2016-06-14 18:01:00 +02:00
|
|
|
/* FIXME: We should call drm_atomic_helper_commit_hw_done() here
|
|
|
|
|
* already, but still need the state for the delayed optimization. To
|
|
|
|
|
* fix this:
|
|
|
|
|
* - wrap the optimization/post_plane_update stuff into a per-crtc work.
|
|
|
|
|
* - schedule that vblank worker _before_ calling hw_done
|
|
|
|
|
* - at the start of commit_tail, cancel it _synchrously
|
|
|
|
|
* - switch over to the vblank wait helper in the core after that since
|
|
|
|
|
* we don't need out special handling any more.
|
|
|
|
|
*/
|
2017-09-04 12:48:33 +02:00
|
|
|
drm_atomic_helper_wait_for_flip_done(dev, state);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now that the vblank has passed, we can go ahead and program the
|
|
|
|
|
* optimal watermarks on platforms that need two-step watermark
|
|
|
|
|
* programming.
|
|
|
|
|
*
|
|
|
|
|
* TODO: Move this (and other cleanup) to an async worker eventually.
|
|
|
|
|
*/
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
|
|
|
|
|
intel_cstate = to_intel_crtc_state(new_crtc_state);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
if (dev_priv->display.optimize_watermarks)
|
2016-11-08 13:55:32 +01:00
|
|
|
dev_priv->display.optimize_watermarks(intel_state,
|
|
|
|
|
intel_cstate);
|
2016-05-24 17:13:53 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
2016-05-24 17:13:53 +02:00
|
|
|
intel_post_plane_update(to_intel_crtc_state(old_crtc_state));
|
|
|
|
|
|
|
|
|
|
if (put_domains[i])
|
|
|
|
|
modeset_put_power_domains(dev_priv, put_domains[i]);
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
|
2016-05-24 17:13:53 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:17 +02:00
|
|
|
if (intel_state->modeset)
|
|
|
|
|
intel_verify_planes(intel_state);
|
|
|
|
|
|
2016-09-22 18:00:28 -03:00
|
|
|
if (intel_state->modeset && intel_can_enable_sagv(state))
|
2016-09-22 18:00:27 -03:00
|
|
|
intel_enable_sagv(dev_priv);
|
drm/i915/skl: Add support for the SAGV, fix underrun hangs
Since the watermark calculations for Skylake are still broken, we're apt
to hitting underruns very easily under multi-monitor configurations.
While it would be lovely if this was fixed, it's not. Another problem
that's been coming from this however, is the mysterious issue of
underruns causing full system hangs. An easy way to reproduce this with
a skylake system:
- Get a laptop with a skylake GPU, and hook up two external monitors to
it
- Move the cursor from the built-in LCD to one of the external displays
as quickly as you can
- You'll get a few pipe underruns, and eventually the entire system will
just freeze.
After doing a lot of investigation and reading through the bspec, I
found the existence of the SAGV, which is responsible for adjusting the
system agent voltage and clock frequencies depending on how much power
we need. According to the bspec:
"The display engine access to system memory is blocked during the
adjustment time. SAGV defaults to enabled. Software must use the
GT-driver pcode mailbox to disable SAGV when the display engine is not
able to tolerate the blocking time."
The rest of the bspec goes on to explain that software can simply leave
the SAGV enabled, and disable it when we use interlaced pipes/have more
then one pipe active.
Sure enough, with this patchset the system hangs resulting from pipe
underruns on Skylake have completely vanished on my T460s. Additionally,
the bspec mentions turning off the SAGV with more then one pipe enabled
as a workaround for display underruns. While this patch doesn't entirely
fix that, it looks like it does improve the situation a little bit so
it's likely this is going to be required to make watermarks on Skylake
fully functional.
This will still need additional work in the future: we shouldn't be
enabling the SAGV if any of the currently enabled planes can't enable WM
levels that introduce latencies >= 30 µs.
Changes since v11:
- Add skl_can_enable_sagv()
- Make sure we don't enable SAGV when not all planes can enable
watermarks >= the SAGV engine block time. I was originally going to
save this for later, but I recently managed to run into a machine
that was having problems with a single pipe configuration + SAGV.
- Make comparisons to I915_SKL_SAGV_NOT_CONTROLLED explicit
- Change I915_SAGV_DYNAMIC_FREQ to I915_SAGV_ENABLE
- Move printks outside of mutexes
- Don't print error messages twice
Changes since v10:
- Apparently sandybridge_pcode_read actually writes values and reads
them back, despite it's misleading function name. This means we've
been doing this mostly wrong and have been writing garbage to the
SAGV control. Because of this, we no longer attempt to read the SAGV
status during initialization (since there are no helpers for this).
- mlankhorst noticed that this patch was breaking on some very early
pre-release Skylake machines, which apparently don't allow you to
disable the SAGV. To prevent machines from failing tests due to SAGV
errors, if the first time we try to control the SAGV results in the
mailbox indicating an invalid command, we just disable future attempts
to control the SAGV state by setting dev_priv->skl_sagv_status to
I915_SKL_SAGV_NOT_CONTROLLED and make a note of it in dmesg.
- Move mutex_unlock() a little higher in skl_enable_sagv(). This
doesn't actually fix anything, but lets us release the lock a little
sooner since we're finished with it.
Changes since v9:
- Only enable/disable sagv on Skylake
Changes since v8:
- Add intel_state->modeset guard to the conditional for
skl_enable_sagv()
Changes since v7:
- Remove GEN9_SAGV_LOW_FREQ, replace with GEN9_SAGV_IS_ENABLED (that's
all we use it for anyway)
- Use GEN9_SAGV_IS_ENABLED instead of 0x1 for clarification
- Fix a styling error that snuck past me
Changes since v6:
- Protect skl_enable_sagv() with intel_state->modeset conditional in
intel_atomic_commit_tail()
Changes since v5:
- Don't use is_power_of_2. Makes things confusing
- Don't use the old state to figure out whether or not to
enable/disable the sagv, use the new one
- Split the loop in skl_disable_sagv into it's own function
- Move skl_sagv_enable/disable() calls into intel_atomic_commit_tail()
Changes since v4:
- Use is_power_of_2 against active_crtcs to check whether we have > 1
pipe enabled
- Fix skl_sagv_get_hw_state(): (temp & 0x1) indicates disabled, 0x0
enabled
- Call skl_sagv_enable/disable() from pre/post-plane updates
Changes since v3:
- Use time_before() to compare timeout to jiffies
Changes since v2:
- Really apply minor style nitpicks to patch this time
Changes since v1:
- Added comments about this probably being one of the requirements to
fixing Skylake's watermark issues
- Minor style nitpicks from Matt Roper
- Disable these functions on Broxton, since it doesn't have an SAGV
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471463761-26796-3-git-send-email-cpaul@redhat.com
[mlankhorst: ENOSYS -> ENXIO, whitespace fixes]
2016-08-17 15:55:54 -04:00
|
|
|
|
2016-06-14 18:01:00 +02:00
|
|
|
drm_atomic_helper_commit_hw_done(state);
|
|
|
|
|
|
2017-05-04 12:55:08 +01:00
|
|
|
if (intel_state->modeset) {
|
|
|
|
|
/* As one of the primary mmio accessors, KMS has a high
|
|
|
|
|
* likelihood of triggering bugs in unclaimed access. After we
|
|
|
|
|
* finish modesetting, see if an error has been flagged, and if
|
|
|
|
|
* so enable debugging for the next modeset - and hope we catch
|
|
|
|
|
* the culprit.
|
|
|
|
|
*/
|
|
|
|
|
intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
|
2016-05-24 17:13:53 +02:00
|
|
|
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
|
2017-05-04 12:55:08 +01:00
|
|
|
}
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
drm_atomic_helper_cleanup_planes(dev, state);
|
|
|
|
|
|
2016-06-13 16:13:46 +02:00
|
|
|
drm_atomic_helper_commit_cleanup_done(state);
|
|
|
|
|
|
2016-10-14 13:18:18 +01:00
|
|
|
drm_atomic_state_put(state);
|
2013-04-11 20:22:50 +02:00
|
|
|
|
2017-02-02 20:47:41 +00:00
|
|
|
intel_atomic_helper_free_state(dev_priv);
|
2016-06-14 18:01:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_atomic_commit_work(struct work_struct *work)
|
|
|
|
|
{
|
2016-10-28 13:58:45 +01:00
|
|
|
struct drm_atomic_state *state =
|
|
|
|
|
container_of(work, struct drm_atomic_state, commit_work);
|
|
|
|
|
|
2016-06-14 18:01:00 +02:00
|
|
|
intel_atomic_commit_tail(state);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 13:58:45 +01:00
|
|
|
static int __i915_sw_fence_call
|
|
|
|
|
intel_atomic_commit_ready(struct i915_sw_fence *fence,
|
|
|
|
|
enum i915_sw_fence_notify notify)
|
|
|
|
|
{
|
|
|
|
|
struct intel_atomic_state *state =
|
|
|
|
|
container_of(fence, struct intel_atomic_state, commit_ready);
|
|
|
|
|
|
|
|
|
|
switch (notify) {
|
|
|
|
|
case FENCE_COMPLETE:
|
2017-08-08 10:08:27 +02:00
|
|
|
/* we do blocking waits in the worker, nothing to do here */
|
2016-10-28 13:58:45 +01:00
|
|
|
break;
|
|
|
|
|
case FENCE_FREE:
|
2017-01-23 21:29:39 +00:00
|
|
|
{
|
|
|
|
|
struct intel_atomic_helper *helper =
|
|
|
|
|
&to_i915(state->base.dev)->atomic_helper;
|
|
|
|
|
|
|
|
|
|
if (llist_add(&state->freed, &helper->free_list))
|
|
|
|
|
schedule_work(&helper->free_work);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-28 13:58:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NOTIFY_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
drm/i915: Move fb_bits updating later in atomic_commit
Currently it's part of prepare_fb, still in the first phase of
atomic_commit which might fail. Which means that we need to have some
heuristics in cleanup_fb to figure out whether things failed, or
whether we just clean up the old fbs.
That's fragile, and worse, once we start pipelining commits gets
confused: While the last commit is still getting cleanup up we already
hammer in the new one, and fb_bits aren't refcounted, resulting in
lost bits and WARN_ON galore. We could instead try to make cleanup_fb
more clever, but a simpler fix is to postpone the fb_bits tracking
past the point of no return, where we commit all the software state.
That also makes conceptually more sense, since fb_bits must be updated
synchronously from the ioctl (they track usage from userspace pov, not
from the hw pov), right before we're fully committed to the updated.
This fixes WARNING splats from track_fb with page_flip implemented
through atomic_commit.
Testcase: igt/kms_flip/flip-vs-rmfb
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465827229-1704-4-git-send-email-daniel.vetter@ffwll.ch
2016-06-13 16:13:48 +02:00
|
|
|
static void intel_atomic_track_fbs(struct drm_atomic_state *state)
|
|
|
|
|
{
|
2017-03-09 15:52:04 +01:00
|
|
|
struct drm_plane_state *old_plane_state, *new_plane_state;
|
drm/i915: Move fb_bits updating later in atomic_commit
Currently it's part of prepare_fb, still in the first phase of
atomic_commit which might fail. Which means that we need to have some
heuristics in cleanup_fb to figure out whether things failed, or
whether we just clean up the old fbs.
That's fragile, and worse, once we start pipelining commits gets
confused: While the last commit is still getting cleanup up we already
hammer in the new one, and fb_bits aren't refcounted, resulting in
lost bits and WARN_ON galore. We could instead try to make cleanup_fb
more clever, but a simpler fix is to postpone the fb_bits tracking
past the point of no return, where we commit all the software state.
That also makes conceptually more sense, since fb_bits must be updated
synchronously from the ioctl (they track usage from userspace pov, not
from the hw pov), right before we're fully committed to the updated.
This fixes WARNING splats from track_fb with page_flip implemented
through atomic_commit.
Testcase: igt/kms_flip/flip-vs-rmfb
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465827229-1704-4-git-send-email-daniel.vetter@ffwll.ch
2016-06-13 16:13:48 +02:00
|
|
|
struct drm_plane *plane;
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i)
|
2016-08-04 16:32:37 +01:00
|
|
|
i915_gem_track_fb(intel_fb_obj(old_plane_state->fb),
|
2017-03-09 15:52:04 +01:00
|
|
|
intel_fb_obj(new_plane_state->fb),
|
2016-08-04 16:32:37 +01:00
|
|
|
to_intel_plane(plane)->frontbuffer_bit);
|
drm/i915: Move fb_bits updating later in atomic_commit
Currently it's part of prepare_fb, still in the first phase of
atomic_commit which might fail. Which means that we need to have some
heuristics in cleanup_fb to figure out whether things failed, or
whether we just clean up the old fbs.
That's fragile, and worse, once we start pipelining commits gets
confused: While the last commit is still getting cleanup up we already
hammer in the new one, and fb_bits aren't refcounted, resulting in
lost bits and WARN_ON galore. We could instead try to make cleanup_fb
more clever, but a simpler fix is to postpone the fb_bits tracking
past the point of no return, where we commit all the software state.
That also makes conceptually more sense, since fb_bits must be updated
synchronously from the ioctl (they track usage from userspace pov, not
from the hw pov), right before we're fully committed to the updated.
This fixes WARNING splats from track_fb with page_flip implemented
through atomic_commit.
Testcase: igt/kms_flip/flip-vs-rmfb
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465827229-1704-4-git-send-email-daniel.vetter@ffwll.ch
2016-06-13 16:13:48 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-14 18:01:00 +02:00
|
|
|
/**
|
|
|
|
|
* intel_atomic_commit - commit validated state object
|
|
|
|
|
* @dev: DRM device
|
|
|
|
|
* @state: the top-level driver state object
|
|
|
|
|
* @nonblock: nonblocking commit
|
|
|
|
|
*
|
|
|
|
|
* This function commits a top-level state object that has been validated
|
|
|
|
|
* with drm_atomic_helper_check().
|
|
|
|
|
*
|
|
|
|
|
* RETURNS
|
|
|
|
|
* Zero for success or -errno.
|
|
|
|
|
*/
|
|
|
|
|
static int intel_atomic_commit(struct drm_device *dev,
|
|
|
|
|
struct drm_atomic_state *state,
|
|
|
|
|
bool nonblock)
|
|
|
|
|
{
|
|
|
|
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-06-14 18:01:00 +02:00
|
|
|
int ret = 0;
|
|
|
|
|
|
2016-10-28 13:58:45 +01:00
|
|
|
drm_atomic_state_get(state);
|
|
|
|
|
i915_sw_fence_init(&intel_state->commit_ready,
|
|
|
|
|
intel_atomic_commit_ready);
|
2016-06-14 18:01:00 +02:00
|
|
|
|
2017-03-29 17:21:23 +03:00
|
|
|
/*
|
|
|
|
|
* The intel_legacy_cursor_update() fast path takes care
|
|
|
|
|
* of avoiding the vblank waits for simple cursor
|
|
|
|
|
* movement and flips. For cursor on/off and size changes,
|
|
|
|
|
* we want to perform the vblank waits so that watermark
|
|
|
|
|
* updates happen during the correct frames. Gen9+ have
|
|
|
|
|
* double buffered watermarks and so shouldn't need this.
|
|
|
|
|
*
|
2017-09-19 14:14:18 +02:00
|
|
|
* Unset state->legacy_cursor_update before the call to
|
|
|
|
|
* drm_atomic_helper_setup_commit() because otherwise
|
|
|
|
|
* drm_atomic_helper_wait_for_flip_done() is a noop and
|
|
|
|
|
* we get FIFO underruns because we didn't wait
|
|
|
|
|
* for vblank.
|
2017-03-29 17:21:23 +03:00
|
|
|
*
|
|
|
|
|
* FIXME doing watermarks and fb cleanup from a vblank worker
|
|
|
|
|
* (assuming we had any) would solve these problems.
|
|
|
|
|
*/
|
2017-09-19 14:14:19 +02:00
|
|
|
if (INTEL_GEN(dev_priv) < 9 && state->legacy_cursor_update) {
|
|
|
|
|
struct intel_crtc_state *new_crtc_state;
|
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for_each_new_intel_crtc_in_state(intel_state, crtc, new_crtc_state, i)
|
|
|
|
|
if (new_crtc_state->wm.need_postvbl_update ||
|
|
|
|
|
new_crtc_state->update_wm_post)
|
|
|
|
|
state->legacy_cursor_update = false;
|
|
|
|
|
}
|
2017-03-29 17:21:23 +03:00
|
|
|
|
2017-09-19 14:14:18 +02:00
|
|
|
ret = intel_atomic_prepare_commit(dev, state);
|
|
|
|
|
if (ret) {
|
|
|
|
|
DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
|
|
|
|
|
i915_sw_fence_commit(&intel_state->commit_ready);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = drm_atomic_helper_setup_commit(state, nonblock);
|
|
|
|
|
if (!ret)
|
|
|
|
|
ret = drm_atomic_helper_swap_state(state, true);
|
|
|
|
|
|
2017-07-11 16:33:07 +02:00
|
|
|
if (ret) {
|
|
|
|
|
i915_sw_fence_commit(&intel_state->commit_ready);
|
|
|
|
|
|
|
|
|
|
drm_atomic_helper_cleanup_planes(dev, state);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2016-06-14 18:01:00 +02:00
|
|
|
dev_priv->wm.distrust_bios_wm = false;
|
2016-12-29 17:22:08 +02:00
|
|
|
intel_shared_dpll_swap_state(state);
|
drm/i915: Move fb_bits updating later in atomic_commit
Currently it's part of prepare_fb, still in the first phase of
atomic_commit which might fail. Which means that we need to have some
heuristics in cleanup_fb to figure out whether things failed, or
whether we just clean up the old fbs.
That's fragile, and worse, once we start pipelining commits gets
confused: While the last commit is still getting cleanup up we already
hammer in the new one, and fb_bits aren't refcounted, resulting in
lost bits and WARN_ON galore. We could instead try to make cleanup_fb
more clever, but a simpler fix is to postpone the fb_bits tracking
past the point of no return, where we commit all the software state.
That also makes conceptually more sense, since fb_bits must be updated
synchronously from the ioctl (they track usage from userspace pov, not
from the hw pov), right before we're fully committed to the updated.
This fixes WARNING splats from track_fb with page_flip implemented
through atomic_commit.
Testcase: igt/kms_flip/flip-vs-rmfb
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1465827229-1704-4-git-send-email-daniel.vetter@ffwll.ch
2016-06-13 16:13:48 +02:00
|
|
|
intel_atomic_track_fbs(state);
|
2016-06-14 18:01:00 +02:00
|
|
|
|
2016-11-08 13:55:40 +01:00
|
|
|
if (intel_state->modeset) {
|
2017-08-30 21:57:03 +03:00
|
|
|
memcpy(dev_priv->min_cdclk, intel_state->min_cdclk,
|
|
|
|
|
sizeof(intel_state->min_cdclk));
|
2017-10-24 12:52:14 +03:00
|
|
|
memcpy(dev_priv->min_voltage_level,
|
|
|
|
|
intel_state->min_voltage_level,
|
|
|
|
|
sizeof(intel_state->min_voltage_level));
|
2016-11-08 13:55:40 +01:00
|
|
|
dev_priv->active_crtcs = intel_state->active_crtcs;
|
2017-01-20 20:21:59 +02:00
|
|
|
dev_priv->cdclk.logical = intel_state->cdclk.logical;
|
|
|
|
|
dev_priv->cdclk.actual = intel_state->cdclk.actual;
|
2016-11-08 13:55:40 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-14 13:18:18 +01:00
|
|
|
drm_atomic_state_get(state);
|
2017-08-08 10:08:27 +02:00
|
|
|
INIT_WORK(&state->commit_work, intel_atomic_commit_work);
|
2016-10-28 13:58:45 +01:00
|
|
|
|
|
|
|
|
i915_sw_fence_commit(&intel_state->commit_ready);
|
2017-11-13 15:36:22 +02:00
|
|
|
if (nonblock && intel_state->modeset) {
|
|
|
|
|
queue_work(dev_priv->modeset_wq, &state->commit_work);
|
|
|
|
|
} else if (nonblock) {
|
2017-08-08 10:08:27 +02:00
|
|
|
queue_work(system_unbound_wq, &state->commit_work);
|
2017-11-13 15:36:22 +02:00
|
|
|
} else {
|
|
|
|
|
if (intel_state->modeset)
|
|
|
|
|
flush_workqueue(dev_priv->modeset_wq);
|
2016-06-14 18:01:00 +02:00
|
|
|
intel_atomic_commit_tail(state);
|
2017-11-13 15:36:22 +02:00
|
|
|
}
|
2015-12-16 09:26:48 +02:00
|
|
|
|
2015-07-13 16:30:30 +02:00
|
|
|
return 0;
|
2014-11-05 14:26:06 -08:00
|
|
|
}
|
|
|
|
|
|
2011-04-12 18:06:51 +01:00
|
|
|
static const struct drm_crtc_funcs intel_crtc_funcs = {
|
2017-04-03 10:32:57 +02:00
|
|
|
.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
2015-07-13 16:30:30 +02:00
|
|
|
.set_config = drm_atomic_helper_set_config,
|
2011-04-12 18:06:51 +01:00
|
|
|
.destroy = intel_crtc_destroy,
|
2016-12-22 11:33:23 +01:00
|
|
|
.page_flip = drm_atomic_helper_page_flip,
|
2015-01-21 16:35:47 -08:00
|
|
|
.atomic_duplicate_state = intel_crtc_duplicate_state,
|
|
|
|
|
.atomic_destroy_state = intel_crtc_destroy_state,
|
2017-01-10 14:43:04 +01:00
|
|
|
.set_crc_source = intel_crtc_set_crc_source,
|
2011-04-12 18:06:51 +01:00
|
|
|
};
|
|
|
|
|
|
2017-08-17 13:37:06 +01:00
|
|
|
struct wait_rps_boost {
|
|
|
|
|
struct wait_queue_entry wait;
|
|
|
|
|
|
|
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
struct drm_i915_gem_request *request;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int do_rps_boost(struct wait_queue_entry *_wait,
|
|
|
|
|
unsigned mode, int sync, void *key)
|
|
|
|
|
{
|
|
|
|
|
struct wait_rps_boost *wait = container_of(_wait, typeof(*wait), wait);
|
|
|
|
|
struct drm_i915_gem_request *rq = wait->request;
|
|
|
|
|
|
2018-01-18 13:16:09 +00:00
|
|
|
/*
|
|
|
|
|
* If we missed the vblank, but the request is already running it
|
|
|
|
|
* is reasonable to assume that it will complete before the next
|
|
|
|
|
* vblank without our intervention, so leave RPS alone.
|
|
|
|
|
*/
|
|
|
|
|
if (!i915_gem_request_started(rq))
|
|
|
|
|
gen6_rps_boost(rq, NULL);
|
2017-08-17 13:37:06 +01:00
|
|
|
i915_gem_request_put(rq);
|
|
|
|
|
|
|
|
|
|
drm_crtc_vblank_put(wait->crtc);
|
|
|
|
|
|
|
|
|
|
list_del(&wait->wait.entry);
|
|
|
|
|
kfree(wait);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void add_rps_boost_after_vblank(struct drm_crtc *crtc,
|
|
|
|
|
struct dma_fence *fence)
|
|
|
|
|
{
|
|
|
|
|
struct wait_rps_boost *wait;
|
|
|
|
|
|
|
|
|
|
if (!dma_fence_is_i915(fence))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (INTEL_GEN(to_i915(crtc->dev)) < 6)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (drm_crtc_vblank_get(crtc))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
wait = kmalloc(sizeof(*wait), GFP_KERNEL);
|
|
|
|
|
if (!wait) {
|
|
|
|
|
drm_crtc_vblank_put(crtc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wait->request = to_request(dma_fence_get(fence));
|
|
|
|
|
wait->crtc = crtc;
|
|
|
|
|
|
|
|
|
|
wait->wait.func = do_rps_boost;
|
|
|
|
|
wait->wait.flags = 0;
|
|
|
|
|
|
|
|
|
|
add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-01 15:40:14 -08:00
|
|
|
/**
|
|
|
|
|
* intel_prepare_plane_fb - Prepare fb for usage on plane
|
|
|
|
|
* @plane: drm plane to prepare for
|
|
|
|
|
* @fb: framebuffer to prepare for presentation
|
|
|
|
|
*
|
|
|
|
|
* Prepares a framebuffer for usage on a display plane. Generally this
|
|
|
|
|
* involves pinning the underlying object and updating the frontbuffer tracking
|
|
|
|
|
* bits. Some older platforms need special physical address handling for
|
|
|
|
|
* cursor planes.
|
|
|
|
|
*
|
2015-08-18 13:40:05 +02:00
|
|
|
* Must be called with struct_mutex held.
|
|
|
|
|
*
|
2014-12-01 15:40:14 -08:00
|
|
|
* Returns 0 on success, negative error code on failure.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
intel_prepare_plane_fb(struct drm_plane *plane,
|
2016-08-18 19:00:16 +01:00
|
|
|
struct drm_plane_state *new_state)
|
2014-05-29 08:06:54 -07:00
|
|
|
{
|
2016-10-28 13:58:45 +01:00
|
|
|
struct intel_atomic_state *intel_state =
|
|
|
|
|
to_intel_atomic_state(new_state->state);
|
2016-11-09 11:30:45 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->dev);
|
2015-09-02 10:42:40 +02:00
|
|
|
struct drm_framebuffer *fb = new_state->fb;
|
2014-12-01 15:40:14 -08:00
|
|
|
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
2015-09-23 13:27:08 +02:00
|
|
|
struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb);
|
2016-10-28 13:58:45 +01:00
|
|
|
int ret;
|
2014-05-29 08:06:54 -07:00
|
|
|
|
2015-08-18 13:40:05 +02:00
|
|
|
if (old_obj) {
|
|
|
|
|
struct drm_crtc_state *crtc_state =
|
2016-10-28 13:58:45 +01:00
|
|
|
drm_atomic_get_existing_crtc_state(new_state->state,
|
|
|
|
|
plane->state->crtc);
|
2015-08-18 13:40:05 +02:00
|
|
|
|
|
|
|
|
/* Big Hammer, we also need to ensure that any pending
|
|
|
|
|
* MI_WAIT_FOR_EVENT inside a user batch buffer on the
|
|
|
|
|
* current scanout is retired before unpinning the old
|
|
|
|
|
* framebuffer. Note that we rely on userspace rendering
|
|
|
|
|
* into the buffer attached to the pipe they are waiting
|
|
|
|
|
* on. If not, userspace generates a GPU hang with IPEHR
|
|
|
|
|
* point to the MI_WAIT_FOR_EVENT.
|
|
|
|
|
*
|
|
|
|
|
* This should only fail upon a hung GPU, in which case we
|
|
|
|
|
* can safely continue.
|
|
|
|
|
*/
|
2016-10-28 13:58:45 +01:00
|
|
|
if (needs_modeset(crtc_state)) {
|
|
|
|
|
ret = i915_sw_fence_await_reservation(&intel_state->commit_ready,
|
|
|
|
|
old_obj->resv, NULL,
|
|
|
|
|
false, 0,
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
drm/i915: Prevent leaking of -EIO from i915_wait_request()
Reporting -EIO from i915_wait_request() has proven very troublematic
over the years, with numerous hard-to-reproduce bugs cropping up in the
corner case of where a reset occurs and the code wasn't expecting such
an error.
If the we reset the GPU or have detected a hang and wish to reset the
GPU, the request is forcibly complete and the wait broken. Currently, we
report either -EAGAIN or -EIO in order for the caller to retreat and
restart the wait (if appropriate) after dropping and then reacquiring
the struct_mutex (essential to allow the GPU reset to proceed). However,
if we take the view that the request is complete (no further work will
be done on it by the GPU because it is dead and soon to be reset), then
we can proceed with the task at hand and then drop the struct_mutex
allowing the reset to occur. This transfers the burden of checking
whether it is safe to proceed to the caller, which in all but one
instance it is safe - completely eliminating the source of all spurious
-EIO.
Of note, we only have two API entry points where we expect that
userspace can observe an EIO. First is when submitting an execbuf, if
the GPU is terminally wedged, then the operation cannot succeed and an
-EIO is reported. Secondly, existing userspace uses the throttle ioctl
to detect an already wedged GPU before starting using HW acceleration
(or to confirm that the GPU is wedged after an error condition). So if
the GPU is wedged when the user calls throttle, also report -EIO.
v2: Split more carefully the change to i915_wait_request() and assorted
ABI from the reset handling.
v3: Add a couple of WARN_ON(EIO) to the interruptible modesetting code
so that we don't start to leak EIO there in future (and break our hang
resistant modesetting).
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1460565315-7748-9-git-send-email-chris@chris-wilson.co.uk
Link: http://patchwork.freedesktop.org/patch/msgid/1460565315-7748-1-git-send-email-chris@chris-wilson.co.uk
2016-04-13 17:35:08 +01:00
|
|
|
}
|
2015-08-18 13:40:05 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-28 13:58:45 +01:00
|
|
|
if (new_state->fence) { /* explicit fencing */
|
|
|
|
|
ret = i915_sw_fence_await_dma_fence(&intel_state->commit_ready,
|
|
|
|
|
new_state->fence,
|
|
|
|
|
I915_FENCE_TIMEOUT,
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-17 08:28:47 +01:00
|
|
|
if (!obj)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2017-07-26 17:00:38 +01:00
|
|
|
ret = i915_gem_object_pin_pages(obj);
|
2017-07-26 17:00:36 +01:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2017-07-26 17:00:38 +01:00
|
|
|
ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
|
|
|
|
|
if (ret) {
|
|
|
|
|
i915_gem_object_unpin_pages(obj);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-26 17:00:36 +01:00
|
|
|
if (plane->type == DRM_PLANE_TYPE_CURSOR &&
|
|
|
|
|
INTEL_INFO(dev_priv)->cursor_needs_physical) {
|
|
|
|
|
const int align = intel_cursor_alignment(dev_priv);
|
|
|
|
|
|
|
|
|
|
ret = i915_gem_object_attach_phys(obj, align);
|
|
|
|
|
} else {
|
|
|
|
|
struct i915_vma *vma;
|
|
|
|
|
|
|
|
|
|
vma = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
|
|
|
|
|
if (!IS_ERR(vma))
|
|
|
|
|
to_intel_plane_state(new_state)->vma = vma;
|
|
|
|
|
else
|
|
|
|
|
ret = PTR_ERR(vma);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dev_priv->drm.struct_mutex);
|
2017-07-26 17:00:38 +01:00
|
|
|
i915_gem_object_unpin_pages(obj);
|
2017-07-26 17:00:36 +01:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2016-10-28 13:58:45 +01:00
|
|
|
if (!new_state->fence) { /* implicit fencing */
|
2017-08-17 13:37:06 +01:00
|
|
|
struct dma_fence *fence;
|
|
|
|
|
|
2016-10-28 13:58:45 +01:00
|
|
|
ret = i915_sw_fence_await_reservation(&intel_state->commit_ready,
|
|
|
|
|
obj->resv, NULL,
|
|
|
|
|
false, I915_FENCE_TIMEOUT,
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2017-08-17 13:37:06 +01:00
|
|
|
|
|
|
|
|
fence = reservation_object_get_excl_rcu(obj->resv);
|
|
|
|
|
if (fence) {
|
|
|
|
|
add_rps_boost_after_vblank(new_state->crtc, fence);
|
|
|
|
|
dma_fence_put(fence);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
add_rps_boost_after_vblank(new_state->crtc, new_state->fence);
|
2016-10-28 13:58:45 +01:00
|
|
|
}
|
2016-05-24 17:13:53 +02:00
|
|
|
|
drm/i915: Move GEM activity tracking into a common struct reservation_object
In preparation to support many distinct timelines, we need to expand the
activity tracking on the GEM object to handle more than just a request
per engine. We already use the struct reservation_object on the dma-buf
to handle many fence contexts, so integrating that into the GEM object
itself is the preferred solution. (For example, we can now share the same
reservation_object between every consumer/producer using this buffer and
skip the manual import/export via dma-buf.)
v2: Reimplement busy-ioctl (by walking the reservation object), postpone
the ABI change for another day. Similarly use the reservation object to
find the last_write request (if active and from i915) for choosing
display CS flips.
Caveats:
* busy-ioctl: busy-ioctl only reports on the native fences, it will not
warn of stalls (in set-domain-ioctl, pread/pwrite etc) if the object is
being rendered to by external fences. It also will not report the same
busy state as wait-ioctl (or polling on the dma-buf) in the same
circumstances. On the plus side, it does retain reporting of which
*i915* engines are engaged with this object.
* non-blocking atomic modesets take a step backwards as the wait for
render completion blocks the ioctl. This is fixed in a subsequent
patch to use a fence instead for awaiting on the rendering, see
"drm/i915: Restore nonblocking awaits for modesetting"
* dynamic array manipulation for shared-fences in reservation is slower
than the previous lockless static assignment (e.g. gem_exec_lut_handle
runtime on ivb goes from 42s to 66s), mainly due to atomic operations
(maintaining the fence refcounts).
* loss of object-level retirement callbacks, emulated by VMA retirement
tracking.
* minor loss of object-level last activity information from debugfs,
could be replaced with per-vma information if desired
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161028125858.23563-21-chris@chris-wilson.co.uk
2016-10-28 13:58:44 +01:00
|
|
|
return 0;
|
2014-12-01 15:40:14 -08:00
|
|
|
}
|
|
|
|
|
|
2014-12-02 07:45:25 -08:00
|
|
|
/**
|
|
|
|
|
* intel_cleanup_plane_fb - Cleans up an fb after plane use
|
|
|
|
|
* @plane: drm plane to clean up for
|
|
|
|
|
* @fb: old framebuffer that was on plane
|
|
|
|
|
*
|
|
|
|
|
* Cleans up a framebuffer that has just been removed from a plane.
|
2015-08-18 13:40:05 +02:00
|
|
|
*
|
|
|
|
|
* Must be called with struct_mutex held.
|
2014-12-02 07:45:25 -08:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
intel_cleanup_plane_fb(struct drm_plane *plane,
|
2016-08-18 19:00:16 +01:00
|
|
|
struct drm_plane_state *old_state)
|
2014-12-02 07:45:25 -08:00
|
|
|
{
|
2017-01-16 15:21:27 +00:00
|
|
|
struct i915_vma *vma;
|
2014-12-02 07:45:25 -08:00
|
|
|
|
2017-01-16 15:21:27 +00:00
|
|
|
/* Should only be called after a successful intel_prepare_plane_fb()! */
|
|
|
|
|
vma = fetch_and_zero(&to_intel_plane_state(old_state)->vma);
|
2017-07-26 17:00:36 +01:00
|
|
|
if (vma) {
|
|
|
|
|
mutex_lock(&plane->dev->struct_mutex);
|
2017-01-16 15:21:27 +00:00
|
|
|
intel_unpin_fb_vma(vma);
|
2017-07-26 17:00:36 +01:00
|
|
|
mutex_unlock(&plane->dev->struct_mutex);
|
|
|
|
|
}
|
2014-05-29 08:06:54 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-27 13:48:39 -07:00
|
|
|
int
|
|
|
|
|
skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state)
|
|
|
|
|
{
|
2017-02-23 09:15:58 +02:00
|
|
|
struct drm_i915_private *dev_priv;
|
2015-04-27 13:48:39 -07:00
|
|
|
int max_scale;
|
2017-02-23 09:15:58 +02:00
|
|
|
int crtc_clock, max_dotclk;
|
2015-04-27 13:48:39 -07:00
|
|
|
|
2015-11-24 11:29:02 +01:00
|
|
|
if (!intel_crtc || !crtc_state->base.enable)
|
2015-04-27 13:48:39 -07:00
|
|
|
return DRM_PLANE_HELPER_NO_SCALING;
|
|
|
|
|
|
2017-02-23 09:15:58 +02:00
|
|
|
dev_priv = to_i915(intel_crtc->base.dev);
|
|
|
|
|
|
2015-04-27 13:48:39 -07:00
|
|
|
crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
|
2017-02-23 09:15:58 +02:00
|
|
|
max_dotclk = to_intel_atomic_state(crtc_state->base.state)->cdclk.logical.cdclk;
|
|
|
|
|
|
2017-10-03 15:31:42 -07:00
|
|
|
if (IS_GEMINILAKE(dev_priv) || INTEL_GEN(dev_priv) >= 10)
|
2017-02-23 09:15:58 +02:00
|
|
|
max_dotclk *= 2;
|
2015-04-27 13:48:39 -07:00
|
|
|
|
2017-02-23 09:15:58 +02:00
|
|
|
if (WARN_ON_ONCE(!crtc_clock || max_dotclk < crtc_clock))
|
2015-04-27 13:48:39 -07:00
|
|
|
return DRM_PLANE_HELPER_NO_SCALING;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* skl max scale is lower of:
|
|
|
|
|
* close to 3 but not 3, -1 is for that purpose
|
|
|
|
|
* or
|
|
|
|
|
* cdclk/crtc_clock
|
|
|
|
|
*/
|
2017-02-23 09:15:58 +02:00
|
|
|
max_scale = min((1 << 16) * 3 - 1,
|
|
|
|
|
(1 << 8) * ((max_dotclk << 8) / crtc_clock));
|
2015-04-27 13:48:39 -07:00
|
|
|
|
|
|
|
|
return max_scale;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 08:06:54 -07:00
|
|
|
static int
|
2017-03-27 21:55:33 +03:00
|
|
|
intel_check_primary_plane(struct intel_plane *plane,
|
2015-06-15 12:33:46 +02:00
|
|
|
struct intel_crtc_state *crtc_state,
|
2014-09-05 17:04:49 -03:00
|
|
|
struct intel_plane_state *state)
|
|
|
|
|
{
|
2017-03-27 21:55:33 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
2014-12-01 15:40:13 -08:00
|
|
|
struct drm_crtc *crtc = state->base.crtc;
|
2015-04-27 13:48:39 -07:00
|
|
|
int min_scale = DRM_PLANE_HELPER_NO_SCALING;
|
2015-06-15 12:33:46 +02:00
|
|
|
int max_scale = DRM_PLANE_HELPER_NO_SCALING;
|
|
|
|
|
bool can_position = false;
|
2016-01-28 16:53:54 +02:00
|
|
|
int ret;
|
2014-05-29 08:06:54 -07:00
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2016-01-15 20:46:53 +02:00
|
|
|
/* use scaler when colorkey is not required */
|
2018-02-02 22:42:31 +02:00
|
|
|
if (!state->ckey.flags) {
|
2016-01-15 20:46:53 +02:00
|
|
|
min_scale = 1;
|
|
|
|
|
max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state);
|
|
|
|
|
}
|
2015-04-10 14:37:28 +05:30
|
|
|
can_position = true;
|
2015-04-27 13:48:39 -07:00
|
|
|
}
|
2015-04-10 14:37:28 +05:30
|
|
|
|
2017-11-01 22:16:19 +02:00
|
|
|
ret = drm_atomic_helper_check_plane_state(&state->base,
|
|
|
|
|
&crtc_state->base,
|
|
|
|
|
&state->clip,
|
|
|
|
|
min_scale, max_scale,
|
|
|
|
|
can_position, true);
|
2016-01-28 16:53:54 +02:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2016-08-15 10:41:47 +02:00
|
|
|
if (!state->base.fb)
|
2016-01-28 16:53:54 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2018-01-16 13:24:14 +02:00
|
|
|
ret = skl_check_plane_surface(crtc_state, state);
|
2016-01-28 16:53:54 +02:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2017-03-23 21:27:09 +02:00
|
|
|
|
|
|
|
|
state->ctl = skl_plane_ctl(crtc_state, state);
|
|
|
|
|
} else {
|
2017-03-23 21:27:10 +02:00
|
|
|
ret = i9xx_check_plane_surface(state);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
2017-03-23 21:27:09 +02:00
|
|
|
state->ctl = i9xx_plane_ctl(crtc_state, state);
|
2016-01-28 16:53:54 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-13 10:11:28 -08:00
|
|
|
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
|
|
|
|
|
state->color_ctl = glk_plane_color_ctl(crtc_state, state);
|
|
|
|
|
|
2016-01-28 16:53:54 +02:00
|
|
|
return 0;
|
2014-10-24 14:51:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
static void intel_begin_crtc_commit(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *old_crtc_state)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->dev;
|
drm/i915/skl: Update plane watermarks atomically during plane updates
Thanks to Ville for suggesting this as a potential solution to pipe
underruns on Skylake.
On Skylake all of the registers for configuring planes, including the
registers for configuring their watermarks, are double buffered. New
values written to them won't take effect until said registers are
"armed", which is done by writing to the PLANE_SURF (or in the case of
cursor planes, the CURBASE register) register.
With this in mind, up until now we've been updating watermarks on skl
like this:
non-modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- intel_pre_plane_update:
- intel_update_watermarks()
- {vblank happens; new watermarks + old plane values => underrun }
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- end vblank evasion
}
or
modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- crtc_enable:
- intel_update_watermarks()
- {vblank happens; new watermarks + old plane values => underrun }
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- end vblank evasion
}
Now we update watermarks atomically like this:
non-modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- intel_pre_plane_update:
- intel_update_watermarks() (wm values aren't written yet)
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- write new wm values
- end vblank evasion
}
modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- crtc_enable:
- intel_update_watermarks() (actual wm values aren't written
yet)
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- write new wm values
- end vblank evasion
}
So this patch moves all of the watermark writes into the right place;
inside of the vblank evasion where we update all of the registers for
each plane. While this patch doesn't fix everything, it does allow us to
update the watermark values in the way the hardware expects us to.
Changes since original patch series:
- Remove mutex_lock/mutex_unlock since they don't do anything and we're
not touching global state
- Move skl_write_cursor_wm/skl_write_plane_wm functions into
intel_pm.c, make externally visible
- Add skl_write_plane_wm calls to skl_update_plane
- Fix conditional for for loop in skl_write_plane_wm (level < max_level
should be level <= max_level)
- Make diagram in commit more accurate to what's actually happening
- Add Fixes:
Changes since v1:
- Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
then just Skylake
- Update description to make it clear this patch doesn't fix everything
- Check if pipes were actually changed before writing watermarks
Changes since v2:
- Write PIPE_WM_LINETIME during vblank evasion
Changes since v3:
- Rebase against new SAGV patch changes
Changes since v4:
- Add a parameter to choose what skl_wm_values struct to use when
writing new plane watermarks
Changes since v5:
- Remove cursor ddb entry write in skl_write_cursor_wm(), defer until
patch 6
- Write WM_LINETIME in intel_begin_crtc_commit()
Changes since v6:
- Remove redundant dirty_pipes check in skl_write_plane_wm (we check
this in all places where we call this function, and it was supposed
to have been removed earlier anyway)
- In i9xx_update_cursor(), use dev_priv->info.gen >= 9 instead of
IS_GEN9(dev_priv). We do this everywhere else and I'd imagine this
needs to be done for gen10 as well
Changes since v7:
- Fix rebase fail (unused variable obj)
- Make struct skl_wm_values *wm const
- Fix indenting
- Use INTEL_GEN() instead of dev_priv->info.gen
Changes since v8:
- Don't forget calls to skl_write_plane_wm() when disabling planes
- Use INTEL_GEN(), not INTEL_INFO()->gen in intel_begin_crtc_commit()
Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
Signed-off-by: Lyude <cpaul@redhat.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
2016-08-22 12:50:08 -04:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-05-24 17:13:53 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2016-11-08 13:55:32 +01:00
|
|
|
struct intel_crtc_state *old_intel_cstate =
|
2016-05-24 17:13:53 +02:00
|
|
|
to_intel_crtc_state(old_crtc_state);
|
2016-11-08 13:55:32 +01:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_crtc_state->state);
|
2017-08-23 18:22:21 +03:00
|
|
|
struct intel_crtc_state *intel_cstate =
|
|
|
|
|
intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc);
|
|
|
|
|
bool modeset = needs_modeset(&intel_cstate->base);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
2017-02-28 15:28:47 +01:00
|
|
|
if (!modeset &&
|
|
|
|
|
(intel_cstate->base.color_mgmt_changed ||
|
|
|
|
|
intel_cstate->update_pipe)) {
|
2017-08-23 18:22:20 +03:00
|
|
|
intel_color_set_csc(&intel_cstate->base);
|
|
|
|
|
intel_color_load_luts(&intel_cstate->base);
|
2017-02-28 15:28:47 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-24 17:13:53 +02:00
|
|
|
/* Perform vblank evasion around commit operation */
|
2017-08-23 18:22:21 +03:00
|
|
|
intel_pipe_update_start(intel_cstate);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
|
|
|
|
if (modeset)
|
2016-11-08 13:55:33 +01:00
|
|
|
goto out;
|
2016-05-24 17:13:53 +02:00
|
|
|
|
2016-11-08 13:55:32 +01:00
|
|
|
if (intel_cstate->update_pipe)
|
2017-08-23 18:22:25 +03:00
|
|
|
intel_update_pipe_config(old_intel_cstate, intel_cstate);
|
2016-11-08 13:55:32 +01:00
|
|
|
else if (INTEL_GEN(dev_priv) >= 9)
|
2016-05-24 17:13:53 +02:00
|
|
|
skl_detach_scalers(intel_crtc);
|
drm/i915/skl: Update plane watermarks atomically during plane updates
Thanks to Ville for suggesting this as a potential solution to pipe
underruns on Skylake.
On Skylake all of the registers for configuring planes, including the
registers for configuring their watermarks, are double buffered. New
values written to them won't take effect until said registers are
"armed", which is done by writing to the PLANE_SURF (or in the case of
cursor planes, the CURBASE register) register.
With this in mind, up until now we've been updating watermarks on skl
like this:
non-modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- intel_pre_plane_update:
- intel_update_watermarks()
- {vblank happens; new watermarks + old plane values => underrun }
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- end vblank evasion
}
or
modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- crtc_enable:
- intel_update_watermarks()
- {vblank happens; new watermarks + old plane values => underrun }
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- end vblank evasion
}
Now we update watermarks atomically like this:
non-modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- intel_pre_plane_update:
- intel_update_watermarks() (wm values aren't written yet)
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- write new wm values
- end vblank evasion
}
modeset {
- calculate (during atomic check phase)
- finish_atomic_commit:
- crtc_enable:
- intel_update_watermarks() (actual wm values aren't written
yet)
- drm_atomic_helper_commit_planes_on_crtc:
- start vblank evasion
- write new plane registers
- write new wm values
- end vblank evasion
}
So this patch moves all of the watermark writes into the right place;
inside of the vblank evasion where we update all of the registers for
each plane. While this patch doesn't fix everything, it does allow us to
update the watermark values in the way the hardware expects us to.
Changes since original patch series:
- Remove mutex_lock/mutex_unlock since they don't do anything and we're
not touching global state
- Move skl_write_cursor_wm/skl_write_plane_wm functions into
intel_pm.c, make externally visible
- Add skl_write_plane_wm calls to skl_update_plane
- Fix conditional for for loop in skl_write_plane_wm (level < max_level
should be level <= max_level)
- Make diagram in commit more accurate to what's actually happening
- Add Fixes:
Changes since v1:
- Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
then just Skylake
- Update description to make it clear this patch doesn't fix everything
- Check if pipes were actually changed before writing watermarks
Changes since v2:
- Write PIPE_WM_LINETIME during vblank evasion
Changes since v3:
- Rebase against new SAGV patch changes
Changes since v4:
- Add a parameter to choose what skl_wm_values struct to use when
writing new plane watermarks
Changes since v5:
- Remove cursor ddb entry write in skl_write_cursor_wm(), defer until
patch 6
- Write WM_LINETIME in intel_begin_crtc_commit()
Changes since v6:
- Remove redundant dirty_pipes check in skl_write_plane_wm (we check
this in all places where we call this function, and it was supposed
to have been removed earlier anyway)
- In i9xx_update_cursor(), use dev_priv->info.gen >= 9 instead of
IS_GEN9(dev_priv). We do this everywhere else and I'd imagine this
needs to be done for gen10 as well
Changes since v7:
- Fix rebase fail (unused variable obj)
- Make struct skl_wm_values *wm const
- Fix indenting
- Use INTEL_GEN() instead of dev_priv->info.gen
Changes since v8:
- Don't forget calls to skl_write_plane_wm() when disabling planes
- Use INTEL_GEN(), not INTEL_INFO()->gen in intel_begin_crtc_commit()
Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
Signed-off-by: Lyude <cpaul@redhat.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
2016-08-22 12:50:08 -04:00
|
|
|
|
2016-11-08 13:55:33 +01:00
|
|
|
out:
|
2016-11-08 13:55:32 +01:00
|
|
|
if (dev_priv->display.atomic_update_watermarks)
|
|
|
|
|
dev_priv->display.atomic_update_watermarks(old_intel_state,
|
|
|
|
|
intel_cstate);
|
2016-05-24 17:13:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_finish_crtc_commit(struct drm_crtc *crtc,
|
|
|
|
|
struct drm_crtc_state *old_crtc_state)
|
|
|
|
|
{
|
2017-11-13 15:40:43 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
2016-05-24 17:13:53 +02:00
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
2017-08-23 18:22:21 +03:00
|
|
|
struct intel_atomic_state *old_intel_state =
|
|
|
|
|
to_intel_atomic_state(old_crtc_state->state);
|
|
|
|
|
struct intel_crtc_state *new_crtc_state =
|
|
|
|
|
intel_atomic_get_new_crtc_state(old_intel_state, intel_crtc);
|
2016-05-24 17:13:53 +02:00
|
|
|
|
2017-08-23 18:22:21 +03:00
|
|
|
intel_pipe_update_end(new_crtc_state);
|
2017-11-13 15:40:43 +01:00
|
|
|
|
|
|
|
|
if (new_crtc_state->update_pipe &&
|
|
|
|
|
!needs_modeset(&new_crtc_state->base) &&
|
|
|
|
|
old_crtc_state->mode.private_flags & I915_MODE_FLAG_INHERITED) {
|
|
|
|
|
if (!IS_GEN2(dev_priv))
|
|
|
|
|
intel_set_cpu_fifo_underrun_reporting(dev_priv, intel_crtc->pipe, true);
|
|
|
|
|
|
|
|
|
|
if (new_crtc_state->has_pch_encoder) {
|
|
|
|
|
enum pipe pch_transcoder =
|
|
|
|
|
intel_crtc_pch_transcoder(intel_crtc);
|
|
|
|
|
|
|
|
|
|
intel_set_pch_fifo_underrun_reporting(dev_priv, pch_transcoder, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-24 17:13:53 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:27:42 -08:00
|
|
|
/**
|
2014-12-23 10:41:51 -08:00
|
|
|
* intel_plane_destroy - destroy a plane
|
|
|
|
|
* @plane: plane to destroy
|
2014-12-04 10:27:42 -08:00
|
|
|
*
|
2014-12-23 10:41:51 -08:00
|
|
|
* Common destruction function for all types of planes (primary, cursor,
|
|
|
|
|
* sprite).
|
2014-12-04 10:27:42 -08:00
|
|
|
*/
|
2014-12-23 10:41:51 -08:00
|
|
|
void intel_plane_destroy(struct drm_plane *plane)
|
2014-05-29 08:06:54 -07:00
|
|
|
{
|
|
|
|
|
drm_plane_cleanup(plane);
|
2016-05-27 20:59:22 +03:00
|
|
|
kfree(to_intel_plane(plane));
|
2014-05-29 08:06:54 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-01 09:58:16 -07:00
|
|
|
static bool i8xx_mod_supported(uint32_t format, uint64_t modifier)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
case DRM_FORMAT_C8:
|
|
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
case DRM_FORMAT_XRGB1555:
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
return modifier == DRM_FORMAT_MOD_LINEAR ||
|
|
|
|
|
modifier == I915_FORMAT_MOD_X_TILED;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool i965_mod_supported(uint32_t format, uint64_t modifier)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
case DRM_FORMAT_C8:
|
|
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
|
|
case DRM_FORMAT_XRGB2101010:
|
|
|
|
|
case DRM_FORMAT_XBGR2101010:
|
|
|
|
|
return modifier == DRM_FORMAT_MOD_LINEAR ||
|
|
|
|
|
modifier == I915_FORMAT_MOD_X_TILED;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool skl_mod_supported(uint32_t format, uint64_t modifier)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
|
|
|
|
if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
|
|
|
|
|
modifier == I915_FORMAT_MOD_Y_TILED_CCS)
|
|
|
|
|
return true;
|
|
|
|
|
/* fall through */
|
|
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
case DRM_FORMAT_XRGB2101010:
|
|
|
|
|
case DRM_FORMAT_XBGR2101010:
|
|
|
|
|
case DRM_FORMAT_YUYV:
|
|
|
|
|
case DRM_FORMAT_YVYU:
|
|
|
|
|
case DRM_FORMAT_UYVY:
|
|
|
|
|
case DRM_FORMAT_VYUY:
|
|
|
|
|
if (modifier == I915_FORMAT_MOD_Yf_TILED)
|
|
|
|
|
return true;
|
|
|
|
|
/* fall through */
|
|
|
|
|
case DRM_FORMAT_C8:
|
|
|
|
|
if (modifier == DRM_FORMAT_MOD_LINEAR ||
|
|
|
|
|
modifier == I915_FORMAT_MOD_X_TILED ||
|
|
|
|
|
modifier == I915_FORMAT_MOD_Y_TILED)
|
|
|
|
|
return true;
|
|
|
|
|
/* fall through */
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool intel_primary_plane_format_mod_supported(struct drm_plane *plane,
|
|
|
|
|
uint32_t format,
|
|
|
|
|
uint64_t modifier)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(plane->dev);
|
|
|
|
|
|
|
|
|
|
if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ((modifier >> 56) != DRM_FORMAT_MOD_VENDOR_INTEL &&
|
|
|
|
|
modifier != DRM_FORMAT_MOD_LINEAR)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
|
|
|
|
return skl_mod_supported(format, modifier);
|
|
|
|
|
else if (INTEL_GEN(dev_priv) >= 4)
|
|
|
|
|
return i965_mod_supported(format, modifier);
|
|
|
|
|
else
|
|
|
|
|
return i8xx_mod_supported(format, modifier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool intel_cursor_plane_format_mod_supported(struct drm_plane *plane,
|
|
|
|
|
uint32_t format,
|
|
|
|
|
uint64_t modifier)
|
|
|
|
|
{
|
|
|
|
|
if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return modifier == DRM_FORMAT_MOD_LINEAR && format == DRM_FORMAT_ARGB8888;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct drm_plane_funcs intel_plane_funcs = {
|
2015-04-08 18:56:53 -07:00
|
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
2014-06-10 08:28:13 -07:00
|
|
|
.destroy = intel_plane_destroy,
|
2015-01-21 16:35:43 -08:00
|
|
|
.atomic_get_property = intel_plane_atomic_get_property,
|
|
|
|
|
.atomic_set_property = intel_plane_atomic_set_property,
|
2014-12-23 10:41:52 -08:00
|
|
|
.atomic_duplicate_state = intel_plane_duplicate_state,
|
|
|
|
|
.atomic_destroy_state = intel_plane_destroy_state,
|
2017-08-01 09:58:16 -07:00
|
|
|
.format_mod_supported = intel_primary_plane_format_mod_supported,
|
2014-05-29 08:06:54 -07:00
|
|
|
};
|
|
|
|
|
|
2016-12-12 11:34:55 +01:00
|
|
|
static int
|
|
|
|
|
intel_legacy_cursor_update(struct drm_plane *plane,
|
|
|
|
|
struct drm_crtc *crtc,
|
|
|
|
|
struct drm_framebuffer *fb,
|
|
|
|
|
int crtc_x, int crtc_y,
|
|
|
|
|
unsigned int crtc_w, unsigned int crtc_h,
|
|
|
|
|
uint32_t src_x, uint32_t src_y,
|
2017-03-22 22:50:41 +01:00
|
|
|
uint32_t src_w, uint32_t src_h,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
2016-12-12 11:34:55 +01:00
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
|
|
|
|
int ret;
|
|
|
|
|
struct drm_plane_state *old_plane_state, *new_plane_state;
|
|
|
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
|
|
struct drm_framebuffer *old_fb;
|
|
|
|
|
struct drm_crtc_state *crtc_state = crtc->state;
|
2017-07-26 17:00:36 +01:00
|
|
|
struct i915_vma *old_vma, *vma;
|
2016-12-12 11:34:55 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When crtc is inactive or there is a modeset pending,
|
|
|
|
|
* wait for it to complete in the slowpath
|
|
|
|
|
*/
|
|
|
|
|
if (!crtc_state->active || needs_modeset(crtc_state) ||
|
|
|
|
|
to_intel_crtc_state(crtc_state)->update_pipe)
|
|
|
|
|
goto slow;
|
|
|
|
|
|
|
|
|
|
old_plane_state = plane->state;
|
2017-09-04 12:48:38 +02:00
|
|
|
/*
|
|
|
|
|
* Don't do an async update if there is an outstanding commit modifying
|
|
|
|
|
* the plane. This prevents our async update's changes from getting
|
|
|
|
|
* overridden by a previous synchronous update's state.
|
|
|
|
|
*/
|
|
|
|
|
if (old_plane_state->commit &&
|
|
|
|
|
!try_wait_for_completion(&old_plane_state->commit->hw_done))
|
|
|
|
|
goto slow;
|
2016-12-12 11:34:55 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If any parameters change that may affect watermarks,
|
|
|
|
|
* take the slowpath. Only changing fb or position should be
|
|
|
|
|
* in the fastpath.
|
|
|
|
|
*/
|
|
|
|
|
if (old_plane_state->crtc != crtc ||
|
|
|
|
|
old_plane_state->src_w != src_w ||
|
|
|
|
|
old_plane_state->src_h != src_h ||
|
|
|
|
|
old_plane_state->crtc_w != crtc_w ||
|
|
|
|
|
old_plane_state->crtc_h != crtc_h ||
|
2017-02-17 17:01:59 +02:00
|
|
|
!old_plane_state->fb != !fb)
|
2016-12-12 11:34:55 +01:00
|
|
|
goto slow;
|
|
|
|
|
|
|
|
|
|
new_plane_state = intel_plane_duplicate_state(plane);
|
|
|
|
|
if (!new_plane_state)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
drm_atomic_set_fb_for_plane(new_plane_state, fb);
|
|
|
|
|
|
|
|
|
|
new_plane_state->src_x = src_x;
|
|
|
|
|
new_plane_state->src_y = src_y;
|
|
|
|
|
new_plane_state->src_w = src_w;
|
|
|
|
|
new_plane_state->src_h = src_h;
|
|
|
|
|
new_plane_state->crtc_x = crtc_x;
|
|
|
|
|
new_plane_state->crtc_y = crtc_y;
|
|
|
|
|
new_plane_state->crtc_w = crtc_w;
|
|
|
|
|
new_plane_state->crtc_h = crtc_h;
|
|
|
|
|
|
|
|
|
|
ret = intel_plane_atomic_check_with_state(to_intel_crtc_state(crtc->state),
|
2017-08-23 18:22:23 +03:00
|
|
|
to_intel_crtc_state(crtc->state), /* FIXME need a new crtc state? */
|
|
|
|
|
to_intel_plane_state(plane->state),
|
2016-12-12 11:34:55 +01:00
|
|
|
to_intel_plane_state(new_plane_state));
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
|
|
ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
|
|
if (INTEL_INFO(dev_priv)->cursor_needs_physical) {
|
2017-03-27 21:55:43 +03:00
|
|
|
int align = intel_cursor_alignment(dev_priv);
|
2016-12-12 11:34:55 +01:00
|
|
|
|
|
|
|
|
ret = i915_gem_object_attach_phys(intel_fb_obj(fb), align);
|
|
|
|
|
if (ret) {
|
|
|
|
|
DRM_DEBUG_KMS("failed to attach phys object\n");
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
vma = intel_pin_and_fence_fb_obj(fb, new_plane_state->rotation);
|
|
|
|
|
if (IS_ERR(vma)) {
|
|
|
|
|
DRM_DEBUG_KMS("failed to pin object\n");
|
|
|
|
|
|
|
|
|
|
ret = PTR_ERR(vma);
|
|
|
|
|
goto out_unlock;
|
|
|
|
|
}
|
2017-01-16 15:21:27 +00:00
|
|
|
|
|
|
|
|
to_intel_plane_state(new_plane_state)->vma = vma;
|
2016-12-12 11:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
old_fb = old_plane_state->fb;
|
|
|
|
|
|
|
|
|
|
i915_gem_track_fb(intel_fb_obj(old_fb), intel_fb_obj(fb),
|
|
|
|
|
intel_plane->frontbuffer_bit);
|
|
|
|
|
|
|
|
|
|
/* Swap plane state */
|
2017-09-04 12:48:38 +02:00
|
|
|
plane->state = new_plane_state;
|
2016-12-12 11:34:55 +01:00
|
|
|
|
2017-03-02 19:15:05 +02:00
|
|
|
if (plane->state->visible) {
|
|
|
|
|
trace_intel_update_plane(plane, to_intel_crtc(crtc));
|
2017-03-27 21:55:33 +03:00
|
|
|
intel_plane->update_plane(intel_plane,
|
2017-02-17 17:01:59 +02:00
|
|
|
to_intel_crtc_state(crtc->state),
|
|
|
|
|
to_intel_plane_state(plane->state));
|
2017-03-02 19:15:05 +02:00
|
|
|
} else {
|
|
|
|
|
trace_intel_disable_plane(plane, to_intel_crtc(crtc));
|
2017-03-27 21:55:33 +03:00
|
|
|
intel_plane->disable_plane(intel_plane, to_intel_crtc(crtc));
|
2017-03-02 19:15:05 +02:00
|
|
|
}
|
2016-12-12 11:34:55 +01:00
|
|
|
|
2017-09-04 12:48:38 +02:00
|
|
|
old_vma = fetch_and_zero(&to_intel_plane_state(old_plane_state)->vma);
|
2017-07-26 17:00:36 +01:00
|
|
|
if (old_vma)
|
|
|
|
|
intel_unpin_fb_vma(old_vma);
|
2016-12-12 11:34:55 +01:00
|
|
|
|
|
|
|
|
out_unlock:
|
|
|
|
|
mutex_unlock(&dev_priv->drm.struct_mutex);
|
|
|
|
|
out_free:
|
2017-09-04 12:48:38 +02:00
|
|
|
if (ret)
|
|
|
|
|
intel_plane_destroy_state(plane, new_plane_state);
|
|
|
|
|
else
|
|
|
|
|
intel_plane_destroy_state(plane, old_plane_state);
|
2016-12-12 11:34:55 +01:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
slow:
|
|
|
|
|
return drm_atomic_helper_update_plane(plane, crtc, fb,
|
|
|
|
|
crtc_x, crtc_y, crtc_w, crtc_h,
|
2017-03-22 22:50:41 +01:00
|
|
|
src_x, src_y, src_w, src_h, ctx);
|
2016-12-12 11:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct drm_plane_funcs intel_cursor_plane_funcs = {
|
|
|
|
|
.update_plane = intel_legacy_cursor_update,
|
|
|
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
|
|
|
.destroy = intel_plane_destroy,
|
|
|
|
|
.atomic_get_property = intel_plane_atomic_get_property,
|
|
|
|
|
.atomic_set_property = intel_plane_atomic_set_property,
|
|
|
|
|
.atomic_duplicate_state = intel_plane_duplicate_state,
|
|
|
|
|
.atomic_destroy_state = intel_plane_destroy_state,
|
2017-08-01 09:58:16 -07:00
|
|
|
.format_mod_supported = intel_cursor_plane_format_mod_supported,
|
2016-12-12 11:34:55 +01:00
|
|
|
};
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
static struct intel_plane *
|
2016-10-31 22:37:00 +02:00
|
|
|
intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
|
2014-05-29 08:06:54 -07:00
|
|
|
{
|
2016-03-21 14:43:22 +00:00
|
|
|
struct intel_plane *primary = NULL;
|
|
|
|
|
struct intel_plane_state *state = NULL;
|
2014-05-29 08:06:54 -07:00
|
|
|
const uint32_t *intel_primary_formats;
|
2016-09-26 19:30:56 +03:00
|
|
|
unsigned int supported_rotations;
|
2015-08-12 16:54:28 +02:00
|
|
|
unsigned int num_formats;
|
2017-08-01 09:58:16 -07:00
|
|
|
const uint64_t *modifiers;
|
2016-03-21 14:43:22 +00:00
|
|
|
int ret;
|
2014-05-29 08:06:54 -07:00
|
|
|
|
|
|
|
|
primary = kzalloc(sizeof(*primary), GFP_KERNEL);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (!primary) {
|
|
|
|
|
ret = -ENOMEM;
|
2016-03-21 14:43:22 +00:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
2014-05-29 08:06:54 -07:00
|
|
|
|
2015-01-21 16:35:41 -08:00
|
|
|
state = intel_create_plane_state(&primary->base);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (!state) {
|
|
|
|
|
ret = -ENOMEM;
|
2016-03-21 14:43:22 +00:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
|
|
|
|
|
2015-01-21 16:35:41 -08:00
|
|
|
primary->base.state = &state->base;
|
2014-12-23 10:41:52 -08:00
|
|
|
|
2014-05-29 08:06:54 -07:00
|
|
|
primary->can_scale = false;
|
|
|
|
|
primary->max_downscale = 1;
|
2016-10-31 22:37:00 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2015-04-27 13:48:39 -07:00
|
|
|
primary->can_scale = true;
|
2015-05-11 14:35:47 -07:00
|
|
|
state->scaler_id = -1;
|
2015-04-27 13:48:39 -07:00
|
|
|
}
|
2014-05-29 08:06:54 -07:00
|
|
|
primary->pipe = pipe;
|
2016-11-08 16:47:11 +02:00
|
|
|
/*
|
|
|
|
|
* On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
|
|
|
|
|
* port is hooked to pipe B. Hence we want plane A feeding pipe B.
|
|
|
|
|
*/
|
|
|
|
|
if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4)
|
2017-11-17 21:19:10 +02:00
|
|
|
primary->i9xx_plane = (enum i9xx_plane_id) !pipe;
|
2016-11-08 16:47:11 +02:00
|
|
|
else
|
2017-11-17 21:19:10 +02:00
|
|
|
primary->i9xx_plane = (enum i9xx_plane_id) pipe;
|
2016-11-22 18:01:56 +02:00
|
|
|
primary->id = PLANE_PRIMARY;
|
2018-01-23 20:33:43 +02:00
|
|
|
primary->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, primary->id);
|
2014-12-01 15:40:16 -08:00
|
|
|
primary->check_plane = intel_check_primary_plane;
|
2014-05-29 08:06:54 -07:00
|
|
|
|
2017-12-22 21:22:28 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2015-05-19 12:29:16 +01:00
|
|
|
intel_primary_formats = skl_primary_formats;
|
|
|
|
|
num_formats = ARRAY_SIZE(skl_primary_formats);
|
2017-08-01 09:58:16 -07:00
|
|
|
|
2017-12-22 21:22:28 +02:00
|
|
|
if (skl_plane_has_ccs(dev_priv, pipe, PLANE_PRIMARY))
|
2017-08-01 09:58:16 -07:00
|
|
|
modifiers = skl_format_modifiers_ccs;
|
|
|
|
|
else
|
|
|
|
|
modifiers = skl_format_modifiers_noccs;
|
2016-01-07 11:54:11 +01:00
|
|
|
|
2017-10-17 23:08:09 +03:00
|
|
|
primary->update_plane = skl_update_plane;
|
2017-10-17 23:08:10 +03:00
|
|
|
primary->disable_plane = skl_disable_plane;
|
2017-11-17 21:19:08 +02:00
|
|
|
primary->get_hw_state = skl_plane_get_hw_state;
|
2016-10-31 22:37:00 +02:00
|
|
|
} else if (INTEL_GEN(dev_priv) >= 4) {
|
2015-05-12 16:13:18 +01:00
|
|
|
intel_primary_formats = i965_primary_formats;
|
|
|
|
|
num_formats = ARRAY_SIZE(i965_primary_formats);
|
2017-08-01 09:58:16 -07:00
|
|
|
modifiers = i9xx_format_modifiers;
|
2016-01-07 11:54:11 +01:00
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
primary->update_plane = i9xx_update_plane;
|
|
|
|
|
primary->disable_plane = i9xx_disable_plane;
|
2017-11-17 21:19:08 +02:00
|
|
|
primary->get_hw_state = i9xx_plane_get_hw_state;
|
2015-05-19 12:29:16 +01:00
|
|
|
} else {
|
|
|
|
|
intel_primary_formats = i8xx_primary_formats;
|
|
|
|
|
num_formats = ARRAY_SIZE(i8xx_primary_formats);
|
2017-08-01 09:58:16 -07:00
|
|
|
modifiers = i9xx_format_modifiers;
|
2016-01-07 11:54:11 +01:00
|
|
|
|
2017-11-17 21:19:10 +02:00
|
|
|
primary->update_plane = i9xx_update_plane;
|
|
|
|
|
primary->disable_plane = i9xx_disable_plane;
|
2017-11-17 21:19:08 +02:00
|
|
|
primary->get_hw_state = i9xx_plane_get_hw_state;
|
2014-05-29 08:06:54 -07:00
|
|
|
}
|
|
|
|
|
|
2016-10-31 22:37:00 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
|
|
|
|
ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
|
|
|
|
|
0, &intel_plane_funcs,
|
2016-05-27 20:59:23 +03:00
|
|
|
intel_primary_formats, num_formats,
|
2017-08-01 09:58:16 -07:00
|
|
|
modifiers,
|
2016-05-27 20:59:23 +03:00
|
|
|
DRM_PLANE_TYPE_PRIMARY,
|
|
|
|
|
"plane 1%c", pipe_name(pipe));
|
2016-10-13 11:03:06 +01:00
|
|
|
else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
|
2016-10-31 22:37:00 +02:00
|
|
|
ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
|
|
|
|
|
0, &intel_plane_funcs,
|
2016-05-27 20:59:23 +03:00
|
|
|
intel_primary_formats, num_formats,
|
2017-08-01 09:58:16 -07:00
|
|
|
modifiers,
|
2016-05-27 20:59:23 +03:00
|
|
|
DRM_PLANE_TYPE_PRIMARY,
|
|
|
|
|
"primary %c", pipe_name(pipe));
|
|
|
|
|
else
|
2016-10-31 22:37:00 +02:00
|
|
|
ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
|
|
|
|
|
0, &intel_plane_funcs,
|
2016-05-27 20:59:23 +03:00
|
|
|
intel_primary_formats, num_formats,
|
2017-08-01 09:58:16 -07:00
|
|
|
modifiers,
|
2016-05-27 20:59:23 +03:00
|
|
|
DRM_PLANE_TYPE_PRIMARY,
|
2017-11-17 21:19:10 +02:00
|
|
|
"plane %c",
|
|
|
|
|
plane_name(primary->i9xx_plane));
|
2016-03-21 14:43:22 +00:00
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
2014-08-22 14:06:04 +05:30
|
|
|
|
2017-12-15 13:38:00 -08:00
|
|
|
if (INTEL_GEN(dev_priv) >= 10) {
|
|
|
|
|
supported_rotations =
|
|
|
|
|
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
|
|
|
|
|
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
|
|
|
|
|
DRM_MODE_REFLECT_X;
|
|
|
|
|
} else if (INTEL_GEN(dev_priv) >= 9) {
|
2016-09-26 19:30:56 +03:00
|
|
|
supported_rotations =
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
|
|
|
|
|
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
|
2016-11-14 18:54:00 +02:00
|
|
|
} else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
|
|
|
|
|
supported_rotations =
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
|
|
|
|
|
DRM_MODE_REFLECT_X;
|
2016-10-25 16:36:13 +10:00
|
|
|
} else if (INTEL_GEN(dev_priv) >= 4) {
|
2016-09-26 19:30:56 +03:00
|
|
|
supported_rotations =
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
|
2016-09-26 19:30:56 +03:00
|
|
|
} else {
|
2017-05-19 16:50:17 -04:00
|
|
|
supported_rotations = DRM_MODE_ROTATE_0;
|
2016-09-26 19:30:56 +03:00
|
|
|
}
|
|
|
|
|
|
2016-10-25 16:36:13 +10:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
2016-09-26 19:30:56 +03:00
|
|
|
drm_plane_create_rotation_property(&primary->base,
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_0,
|
2016-09-26 19:30:56 +03:00
|
|
|
supported_rotations);
|
2014-08-22 14:06:04 +05:30
|
|
|
|
2014-12-23 10:41:52 -08:00
|
|
|
drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
return primary;
|
2016-03-21 14:43:22 +00:00
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
kfree(state);
|
|
|
|
|
kfree(primary);
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
return ERR_PTR(ret);
|
2014-05-29 08:06:54 -07:00
|
|
|
}
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
static struct intel_plane *
|
2017-03-27 21:55:37 +03:00
|
|
|
intel_cursor_plane_create(struct drm_i915_private *dev_priv,
|
|
|
|
|
enum pipe pipe)
|
2014-06-10 08:28:13 -07:00
|
|
|
{
|
2016-03-21 14:43:22 +00:00
|
|
|
struct intel_plane *cursor = NULL;
|
|
|
|
|
struct intel_plane_state *state = NULL;
|
|
|
|
|
int ret;
|
2014-06-10 08:28:13 -07:00
|
|
|
|
|
|
|
|
cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (!cursor) {
|
|
|
|
|
ret = -ENOMEM;
|
2016-03-21 14:43:22 +00:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
2014-06-10 08:28:13 -07:00
|
|
|
|
2015-01-21 16:35:41 -08:00
|
|
|
state = intel_create_plane_state(&cursor->base);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (!state) {
|
|
|
|
|
ret = -ENOMEM;
|
2016-03-21 14:43:22 +00:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
|
|
|
|
|
2015-01-21 16:35:41 -08:00
|
|
|
cursor->base.state = &state->base;
|
2014-12-23 10:41:52 -08:00
|
|
|
|
2014-06-10 08:28:13 -07:00
|
|
|
cursor->can_scale = false;
|
|
|
|
|
cursor->max_downscale = 1;
|
|
|
|
|
cursor->pipe = pipe;
|
2017-11-17 21:19:10 +02:00
|
|
|
cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
|
2016-11-22 18:01:56 +02:00
|
|
|
cursor->id = PLANE_CURSOR;
|
2018-01-23 20:33:43 +02:00
|
|
|
cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
|
2017-03-27 21:55:37 +03:00
|
|
|
|
|
|
|
|
if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
|
|
|
|
|
cursor->update_plane = i845_update_cursor;
|
|
|
|
|
cursor->disable_plane = i845_disable_cursor;
|
2017-11-17 21:19:08 +02:00
|
|
|
cursor->get_hw_state = i845_cursor_get_hw_state;
|
2017-03-27 21:55:39 +03:00
|
|
|
cursor->check_plane = i845_check_cursor;
|
2017-03-27 21:55:37 +03:00
|
|
|
} else {
|
|
|
|
|
cursor->update_plane = i9xx_update_cursor;
|
|
|
|
|
cursor->disable_plane = i9xx_disable_cursor;
|
2017-11-17 21:19:08 +02:00
|
|
|
cursor->get_hw_state = i9xx_cursor_get_hw_state;
|
2017-03-27 21:55:39 +03:00
|
|
|
cursor->check_plane = i9xx_check_cursor;
|
2017-03-27 21:55:37 +03:00
|
|
|
}
|
2014-06-10 08:28:13 -07:00
|
|
|
|
2017-03-27 21:55:35 +03:00
|
|
|
cursor->cursor.base = ~0;
|
|
|
|
|
cursor->cursor.cntl = ~0;
|
2017-03-27 21:55:42 +03:00
|
|
|
|
|
|
|
|
if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
|
|
|
|
|
cursor->cursor.size = ~0;
|
2014-06-10 08:28:13 -07:00
|
|
|
|
2016-10-31 22:37:00 +02:00
|
|
|
ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
|
2016-12-12 11:34:55 +01:00
|
|
|
0, &intel_cursor_plane_funcs,
|
2016-03-21 14:43:22 +00:00
|
|
|
intel_cursor_formats,
|
|
|
|
|
ARRAY_SIZE(intel_cursor_formats),
|
2017-08-01 09:58:16 -07:00
|
|
|
cursor_format_modifiers,
|
|
|
|
|
DRM_PLANE_TYPE_CURSOR,
|
2016-05-27 20:59:23 +03:00
|
|
|
"cursor %c", pipe_name(pipe));
|
2016-03-21 14:43:22 +00:00
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
2014-10-23 07:41:34 -07:00
|
|
|
|
2016-10-25 16:36:13 +10:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
2016-09-26 19:30:56 +03:00
|
|
|
drm_plane_create_rotation_property(&cursor->base,
|
2017-05-19 16:50:17 -04:00
|
|
|
DRM_MODE_ROTATE_0,
|
|
|
|
|
DRM_MODE_ROTATE_0 |
|
|
|
|
|
DRM_MODE_ROTATE_180);
|
2014-10-23 07:41:34 -07:00
|
|
|
|
2016-10-31 22:37:00 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2015-05-11 14:35:47 -07:00
|
|
|
state->scaler_id = -1;
|
|
|
|
|
|
2014-12-23 10:41:52 -08:00
|
|
|
drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
return cursor;
|
2016-03-21 14:43:22 +00:00
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
kfree(state);
|
|
|
|
|
kfree(cursor);
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
return ERR_PTR(ret);
|
2014-06-10 08:28:13 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-29 11:23:14 +05:30
|
|
|
static void intel_crtc_init_scalers(struct intel_crtc *crtc,
|
|
|
|
|
struct intel_crtc_state *crtc_state)
|
2015-04-07 15:28:38 -07:00
|
|
|
{
|
2016-10-31 22:37:01 +02:00
|
|
|
struct intel_crtc_scaler_state *scaler_state =
|
|
|
|
|
&crtc_state->scaler_state;
|
2016-11-29 11:23:14 +05:30
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2015-04-07 15:28:38 -07:00
|
|
|
int i;
|
|
|
|
|
|
2016-11-29 11:23:14 +05:30
|
|
|
crtc->num_scalers = dev_priv->info.num_scalers[crtc->pipe];
|
|
|
|
|
if (!crtc->num_scalers)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-31 22:37:01 +02:00
|
|
|
for (i = 0; i < crtc->num_scalers; i++) {
|
|
|
|
|
struct intel_scaler *scaler = &scaler_state->scalers[i];
|
|
|
|
|
|
|
|
|
|
scaler->in_use = 0;
|
|
|
|
|
scaler->mode = PS_SCALER_MODE_DYN;
|
2015-04-07 15:28:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scaler_state->scaler_id = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-31 22:37:11 +02:00
|
|
|
static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
|
|
|
|
struct intel_crtc *intel_crtc;
|
2015-01-15 14:55:26 +02:00
|
|
|
struct intel_crtc_state *crtc_state = NULL;
|
2016-10-25 18:58:02 +03:00
|
|
|
struct intel_plane *primary = NULL;
|
|
|
|
|
struct intel_plane *cursor = NULL;
|
2016-10-25 18:58:01 +03:00
|
|
|
int sprite, ret;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2013-09-19 14:05:45 +02:00
|
|
|
intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (!intel_crtc)
|
|
|
|
|
return -ENOMEM;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2015-01-15 14:55:26 +02:00
|
|
|
crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (!crtc_state) {
|
|
|
|
|
ret = -ENOMEM;
|
2015-01-15 14:55:26 +02:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
2015-04-21 17:13:24 +03:00
|
|
|
intel_crtc->config = crtc_state;
|
|
|
|
|
intel_crtc->base.state = &crtc_state->base;
|
2015-02-25 11:43:26 -08:00
|
|
|
crtc_state->base.crtc = &intel_crtc->base;
|
2015-01-15 14:55:26 +02:00
|
|
|
|
2016-10-31 22:37:00 +02:00
|
|
|
primary = intel_primary_plane_create(dev_priv, pipe);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (IS_ERR(primary)) {
|
|
|
|
|
ret = PTR_ERR(primary);
|
2014-06-10 08:28:13 -07:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
2016-11-22 18:01:57 +02:00
|
|
|
intel_crtc->plane_ids_mask |= BIT(primary->id);
|
2014-06-10 08:28:13 -07:00
|
|
|
|
2016-10-25 18:58:01 +03:00
|
|
|
for_each_sprite(dev_priv, pipe, sprite) {
|
2016-10-25 18:58:02 +03:00
|
|
|
struct intel_plane *plane;
|
|
|
|
|
|
2016-10-31 22:37:00 +02:00
|
|
|
plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
|
2016-11-07 22:20:56 +02:00
|
|
|
if (IS_ERR(plane)) {
|
2016-10-25 18:58:02 +03:00
|
|
|
ret = PTR_ERR(plane);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2016-11-22 18:01:57 +02:00
|
|
|
intel_crtc->plane_ids_mask |= BIT(plane->id);
|
2016-10-25 18:58:01 +03:00
|
|
|
}
|
|
|
|
|
|
2016-10-31 22:37:00 +02:00
|
|
|
cursor = intel_cursor_plane_create(dev_priv, pipe);
|
2016-11-07 22:20:56 +02:00
|
|
|
if (IS_ERR(cursor)) {
|
2016-10-25 18:58:02 +03:00
|
|
|
ret = PTR_ERR(cursor);
|
2014-06-10 08:28:13 -07:00
|
|
|
goto fail;
|
2016-10-25 18:58:02 +03:00
|
|
|
}
|
2016-11-22 18:01:57 +02:00
|
|
|
intel_crtc->plane_ids_mask |= BIT(cursor->id);
|
2014-06-10 08:28:13 -07:00
|
|
|
|
2016-10-31 22:37:11 +02:00
|
|
|
ret = drm_crtc_init_with_planes(&dev_priv->drm, &intel_crtc->base,
|
2016-10-25 18:58:02 +03:00
|
|
|
&primary->base, &cursor->base,
|
|
|
|
|
&intel_crtc_funcs,
|
2016-05-27 20:59:21 +03:00
|
|
|
"pipe %c", pipe_name(pipe));
|
2014-06-10 08:28:13 -07:00
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2009-09-10 15:28:06 -07:00
|
|
|
intel_crtc->pipe = pipe;
|
|
|
|
|
|
2016-11-29 11:23:14 +05:30
|
|
|
/* initialize shared scalers */
|
|
|
|
|
intel_crtc_init_scalers(intel_crtc, crtc_state);
|
|
|
|
|
|
2009-12-02 13:42:53 -08:00
|
|
|
BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
|
2017-11-17 21:19:15 +02:00
|
|
|
dev_priv->plane_to_crtc_mapping[primary->i9xx_plane] != NULL);
|
|
|
|
|
dev_priv->plane_to_crtc_mapping[primary->i9xx_plane] = intel_crtc;
|
2016-10-31 22:37:05 +02:00
|
|
|
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = intel_crtc;
|
2009-12-02 13:42:53 -08:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
|
2014-05-15 15:33:46 +02:00
|
|
|
|
2016-03-16 10:57:14 +00:00
|
|
|
intel_color_init(&intel_crtc->base);
|
|
|
|
|
|
2014-05-15 15:33:46 +02:00
|
|
|
WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
|
2016-10-25 18:58:02 +03:00
|
|
|
|
|
|
|
|
return 0;
|
2014-06-10 08:28:13 -07:00
|
|
|
|
|
|
|
|
fail:
|
2016-10-25 18:58:02 +03:00
|
|
|
/*
|
|
|
|
|
* drm_mode_config_cleanup() will free up any
|
|
|
|
|
* crtcs/planes already initialized.
|
|
|
|
|
*/
|
2015-01-15 14:55:26 +02:00
|
|
|
kfree(crtc_state);
|
2014-06-10 08:28:13 -07:00
|
|
|
kfree(intel_crtc);
|
2016-10-25 18:58:02 +03:00
|
|
|
|
|
|
|
|
return ret;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2013-10-31 18:55:49 +02:00
|
|
|
enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
|
|
|
|
|
{
|
drm: Split connection_mutex out of mode_config.mutex (v3)
After the split-out of crtc locks from the big mode_config.mutex
there's still two major areas it protects:
- Various connector probe states, like connector->status, EDID
properties, probed mode lists and similar information.
- The links from connector->encoder and encoder->crtc and other
modeset-relevant connector state (e.g. properties which control the
panel fitter).
The later is used by modeset operations. But they don't really care
about the former since it's allowed to e.g. enable a disconnected VGA
output or with a mode not in the probed list.
Thus far this hasn't been a problem, but for the atomic modeset
conversion Rob Clark needs to convert all modeset relevant locks into
w/w locks. This is required because the order of acquisition is
determined by how userspace supplies the atomic modeset data. This has
run into troubles in the detect path since the i915 load detect code
needs _both_ protections offered by the mode_config.mutex: It updates
probe state and it needs to change the modeset configuration to enable
the temporary load detect pipe.
The big deal here is that for the probe/detect users of this lock a
plain mutex fits best, but for atomic modesets we really want a w/w
mutex. To fix this lets split out a new connection_mutex lock for the
modeset relevant parts.
For simplicity I've decided to only add one additional lock for all
connector/encoder links and modeset configuration states. We have
piles of different modeset objects in addition to those (like bridges
or panels), so adding per-object locks would be much more effort.
Also, we're guaranteed (at least for now) to do a full modeset if we
need to acquire this lock. Which means that fine-grained locking is
fairly irrelevant compared to the amount of time the full modeset will
take.
I've done a full audit, and there's just a few things that justify
special focus:
- Locking in drm_sysfs.c is almost completely absent. We should
sprinkle mode_config.connection_mutex over this file a bit, but
since it already lacks mode_config.mutex this patch wont make the
situation any worse. This is material for a follow-up patch.
- omap has a omap_framebuffer_flush function which walks the
connector->encoder->crtc links and is called from many contexts.
Some look like they don't acquire mode_config.mutex, so this is
already racy. Again fixing this is material for a separate patch.
- The radeon hot_plug function to retrain DP links looks at
connector->dpms. Currently this happens without any locking, so is
already racy. I think radeon_hotplug_work_func should gain
mutex_lock/unlock calls for the mode_config.connection_mutex.
- Same applies to i915's intel_dp_hot_plug. But again, this is already
racy.
- i915 load_detect code needs to acquire this lock. Which means the
w/w dance due to Rob's work will be nicely contained to _just_ this
function.
I've added fixme comments everywhere where it looks suspicious but in
the sysfs code. After a quick irc discussion with Dave Airlie it
sounds like the lack of locking in there is due to sysfs cleanup fun
at module unload.
v1: original (only compile tested)
v2: missing mutex_init(), etc (from Rob Clark)
v3: i915 needs more care in the conversion:
- Protect the edp pp logic with the connection_mutex.
- Use connection_mutex in the backlight code due to
get_pipe_from_connector.
- Use drm_modeset_lock_all in suspend/resume paths.
- Update lock checks in the overlay code.
Cc: Alex Deucher <alexdeucher@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Rob Clark <robdclark@gmail.com>
2014-05-29 23:54:47 +02:00
|
|
|
struct drm_device *dev = connector->base.dev;
|
2013-10-31 18:55:49 +02:00
|
|
|
|
2013-11-19 12:10:12 -05:00
|
|
|
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
|
2013-10-31 18:55:49 +02:00
|
|
|
|
2017-03-01 10:52:24 +01:00
|
|
|
if (!connector->base.state->crtc)
|
2013-10-31 18:55:49 +02:00
|
|
|
return INVALID_PIPE;
|
|
|
|
|
|
2017-03-01 10:52:24 +01:00
|
|
|
return to_intel_crtc(connector->base.state->crtc)->pipe;
|
2013-10-31 18:55:49 +02:00
|
|
|
}
|
|
|
|
|
|
2018-02-07 18:48:41 +02:00
|
|
|
int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
|
|
|
|
|
struct drm_file *file)
|
2009-04-29 14:43:54 -07:00
|
|
|
{
|
|
|
|
|
struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
|
2014-07-17 23:30:04 -04:00
|
|
|
struct drm_crtc *drmmode_crtc;
|
2009-08-11 16:05:30 +02:00
|
|
|
struct intel_crtc *crtc;
|
2009-04-29 14:43:54 -07:00
|
|
|
|
2017-03-14 23:25:07 -07:00
|
|
|
drmmode_crtc = drm_crtc_find(dev, file, pipe_from_crtc_id->crtc_id);
|
2016-06-24 14:00:24 +01:00
|
|
|
if (!drmmode_crtc)
|
2013-10-17 13:35:03 +03:00
|
|
|
return -ENOENT;
|
2009-04-29 14:43:54 -07:00
|
|
|
|
2014-07-17 23:30:04 -04:00
|
|
|
crtc = to_intel_crtc(drmmode_crtc);
|
2009-08-11 16:05:30 +02:00
|
|
|
pipe_from_crtc_id->pipe = crtc->pipe;
|
2009-04-29 14:43:54 -07:00
|
|
|
|
2009-08-11 16:05:30 +02:00
|
|
|
return 0;
|
2009-04-29 14:43:54 -07:00
|
|
|
}
|
|
|
|
|
|
2012-07-12 20:08:18 +02:00
|
|
|
static int intel_encoder_clones(struct intel_encoder *encoder)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2012-07-12 20:08:18 +02:00
|
|
|
struct drm_device *dev = encoder->base.dev;
|
|
|
|
|
struct intel_encoder *source_encoder;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
int index_mask = 0;
|
|
|
|
|
int entry = 0;
|
|
|
|
|
|
2014-08-05 11:29:37 +01:00
|
|
|
for_each_intel_encoder(dev, source_encoder) {
|
2014-03-03 16:15:28 +02:00
|
|
|
if (encoders_cloneable(encoder, source_encoder))
|
2012-07-12 20:08:18 +02:00
|
|
|
index_mask |= (1 << entry);
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
entry++;
|
|
|
|
|
}
|
2010-09-09 15:14:28 +01:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
return index_mask;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-31 22:37:14 +02:00
|
|
|
static bool has_edp_a(struct drm_i915_private *dev_priv)
|
2010-12-14 19:21:29 +00:00
|
|
|
{
|
2016-10-31 22:37:14 +02:00
|
|
|
if (!IS_MOBILE(dev_priv))
|
2010-12-14 19:21:29 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if ((I915_READ(DP_A) & DP_DETECTED) == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN5(dev_priv) && (I915_READ(FUSE_STRAP) & ILK_eDP_A_DISABLE))
|
2010-12-14 19:21:29 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
static bool intel_crt_present(struct drm_i915_private *dev_priv)
|
2014-06-25 08:24:29 -07:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
2013-12-03 13:56:23 +00:00
|
|
|
return false;
|
|
|
|
|
|
2016-10-13 11:02:58 +01:00
|
|
|
if (IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv))
|
2014-06-25 08:24:29 -07:00
|
|
|
return false;
|
|
|
|
|
|
2016-10-14 10:13:44 +01:00
|
|
|
if (IS_CHERRYVIEW(dev_priv))
|
2014-06-25 08:24:29 -07:00
|
|
|
return false;
|
|
|
|
|
|
2016-10-13 11:02:52 +01:00
|
|
|
if (HAS_PCH_LPT_H(dev_priv) &&
|
|
|
|
|
I915_READ(SFUSE_STRAP) & SFUSE_STRAP_CRT_DISABLED)
|
2015-12-01 23:28:55 +02:00
|
|
|
return false;
|
|
|
|
|
|
2015-12-01 23:29:56 +02:00
|
|
|
/* DDI E can't be used if DDI A requires 4 lanes */
|
2016-10-13 11:02:52 +01:00
|
|
|
if (HAS_DDI(dev_priv) && I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)
|
2015-12-01 23:29:56 +02:00
|
|
|
return false;
|
|
|
|
|
|
drm/i915: Check VBT for CRT port presence on HSW/BDW
Unfortunatey there appear to quite a few HSW/BDW machines (eg.
NUCs, Brix Pro) in the wild with LPT/WPT-H that have no physical
CRT connector and non-working FDI. FDI training fails every
single time on these machines. Dunno, maybe they just didn't
bother wiring it up or something?
Unfortunately all the fuse bits and whatnot are telling us that
the CRT connector is present. And so what we get from this is tons
of false positives from the CI systems due to VGA connector forcing.
I've not found any way to detect this purely from hardware, so we
have to resort to looking at the VBT int_crt_support bit. We used
to check this bit on all platforms, but that broke all the old
machines, so the check was then restricted to VLV only in
commit 84b4e042c470 ("drm/i915: only apply crt_present check on VLV")
Considering HSW and VLV VBT probably got defined around the same time,
it should be reasonably safe to assume that the bits is sane for
HSW/BDW as well. At least I have one copy of some VBT spec here that
says it's meant for both VLV and HSW, and it knows about the bit
(lists it being valid from version 155 onwards). Also I have two
desktop machines with actual CRT ports and both have
int_crt_support==1 in their VBTs.
Also we already trust VBT >= 155 to tell us various details about
the DDI ports, so trusting it a bit more seems reasonable.
As far as VLV goes, the added VBT version check should be fine. Even
if someone has some weird VLV machine with a very old VBT version,
it just means they'll end up with a shadow CRT connector. IIRC the
reason for eliminating the shadow CRT connector on VLV was to speed
up display probing rather than fixing something more serious.
v2: Move the platform checks into the VBT parsing code
Also check that the VBT version is at least 155
v3: Improve commit message (Paulo)
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1449005493-15487-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-01 23:31:33 +02:00
|
|
|
if (!dev_priv->vbt.int_crt_support)
|
2014-06-25 08:24:29 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 14:07:33 +03:00
|
|
|
void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
int pps_num;
|
|
|
|
|
int pps_idx;
|
|
|
|
|
|
|
|
|
|
if (HAS_DDI(dev_priv))
|
|
|
|
|
return;
|
|
|
|
|
/*
|
|
|
|
|
* This w/a is needed at least on CPT/PPT, but to be sure apply it
|
|
|
|
|
* everywhere where registers can be write protected.
|
|
|
|
|
*/
|
|
|
|
|
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
|
|
|
|
pps_num = 2;
|
|
|
|
|
else
|
|
|
|
|
pps_num = 1;
|
|
|
|
|
|
|
|
|
|
for (pps_idx = 0; pps_idx < pps_num; pps_idx++) {
|
|
|
|
|
u32 val = I915_READ(PP_CONTROL(pps_idx));
|
|
|
|
|
|
|
|
|
|
val = (val & ~PANEL_UNLOCK_MASK) | PANEL_UNLOCK_REGS;
|
|
|
|
|
I915_WRITE(PP_CONTROL(pps_idx), val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 14:07:29 +03:00
|
|
|
static void intel_pps_init(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
2016-12-02 10:23:49 +02:00
|
|
|
if (HAS_PCH_SPLIT(dev_priv) || IS_GEN9_LP(dev_priv))
|
2016-08-10 14:07:29 +03:00
|
|
|
dev_priv->pps_mmio_base = PCH_PPS_BASE;
|
|
|
|
|
else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
|
|
|
|
dev_priv->pps_mmio_base = VLV_PPS_BASE;
|
|
|
|
|
else
|
|
|
|
|
dev_priv->pps_mmio_base = PPS_BASE;
|
2016-08-10 14:07:33 +03:00
|
|
|
|
|
|
|
|
intel_pps_unlock_regs_wa(dev_priv);
|
2016-08-10 14:07:29 +03:00
|
|
|
}
|
|
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
static void intel_setup_outputs(struct drm_i915_private *dev_priv)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2010-09-09 15:14:28 +01:00
|
|
|
struct intel_encoder *encoder;
|
2010-07-16 14:46:29 -04:00
|
|
|
bool dpd_is_edp = false;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-08-10 14:07:29 +03:00
|
|
|
intel_pps_init(dev_priv);
|
|
|
|
|
|
2016-06-21 11:51:47 +03:00
|
|
|
/*
|
|
|
|
|
* intel_edp_init_connector() depends on this completing first, to
|
|
|
|
|
* prevent the registeration of both eDP and LVDS and the incorrect
|
|
|
|
|
* sharing of the PPS.
|
|
|
|
|
*/
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_lvds_init(dev_priv);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-11-16 12:32:42 +00:00
|
|
|
if (intel_crt_present(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_crt_init(dev_priv);
|
2010-07-16 14:46:29 -04:00
|
|
|
|
2016-12-02 10:23:49 +02:00
|
|
|
if (IS_GEN9_LP(dev_priv)) {
|
2014-08-19 12:05:01 +05:30
|
|
|
/*
|
|
|
|
|
* FIXME: Broxton doesn't support port detection via the
|
|
|
|
|
* DDI_BUF_CTL_A or SFUSE_STRAP registers, find another way to
|
|
|
|
|
* detect the ports.
|
|
|
|
|
*/
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_ddi_init(dev_priv, PORT_A);
|
|
|
|
|
intel_ddi_init(dev_priv, PORT_B);
|
|
|
|
|
intel_ddi_init(dev_priv, PORT_C);
|
2016-03-22 12:01:50 +02:00
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dsi_init(dev_priv);
|
2016-10-13 11:02:52 +01:00
|
|
|
} else if (HAS_DDI(dev_priv)) {
|
2012-05-09 15:37:27 -03:00
|
|
|
int found;
|
|
|
|
|
|
2015-03-06 15:53:32 -08:00
|
|
|
/*
|
|
|
|
|
* Haswell uses DDI functions to detect digital outputs.
|
|
|
|
|
* On SKL pre-D0 the strap isn't connected, so we assume
|
|
|
|
|
* it's there.
|
|
|
|
|
*/
|
2015-09-18 20:03:35 +03:00
|
|
|
found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED;
|
2015-03-06 15:53:32 -08:00
|
|
|
/* WaIgnoreDDIAStrap: skl */
|
2017-01-23 10:32:37 -08:00
|
|
|
if (found || IS_GEN9_BC(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_ddi_init(dev_priv, PORT_A);
|
2012-05-09 15:37:27 -03:00
|
|
|
|
2018-01-29 15:22:22 -08:00
|
|
|
/* DDI B, C, D, and F detection is indicated by the SFUSE_STRAP
|
2012-05-09 15:37:27 -03:00
|
|
|
* register */
|
|
|
|
|
found = I915_READ(SFUSE_STRAP);
|
|
|
|
|
|
|
|
|
|
if (found & SFUSE_STRAP_DDIB_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_ddi_init(dev_priv, PORT_B);
|
2012-05-09 15:37:27 -03:00
|
|
|
if (found & SFUSE_STRAP_DDIC_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_ddi_init(dev_priv, PORT_C);
|
2012-05-09 15:37:27 -03:00
|
|
|
if (found & SFUSE_STRAP_DDID_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_ddi_init(dev_priv, PORT_D);
|
2018-01-29 15:22:22 -08:00
|
|
|
if (found & SFUSE_STRAP_DDIF_DETECTED)
|
|
|
|
|
intel_ddi_init(dev_priv, PORT_F);
|
2015-08-07 17:35:21 -07:00
|
|
|
/*
|
|
|
|
|
* On SKL we don't have a way to detect DDI-E so we rely on VBT.
|
|
|
|
|
*/
|
2017-01-23 10:32:37 -08:00
|
|
|
if (IS_GEN9_BC(dev_priv) &&
|
2015-08-07 17:35:21 -07:00
|
|
|
(dev_priv->vbt.ddi_port_info[PORT_E].supports_dp ||
|
|
|
|
|
dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi ||
|
|
|
|
|
dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_ddi_init(dev_priv, PORT_E);
|
2015-08-07 17:35:21 -07:00
|
|
|
|
2016-10-13 11:02:53 +01:00
|
|
|
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
2010-07-16 14:46:29 -04:00
|
|
|
int found;
|
2017-08-18 12:30:19 +03:00
|
|
|
dpd_is_edp = intel_dp_is_port_edp(dev_priv, PORT_D);
|
2012-10-27 15:52:05 +02:00
|
|
|
|
2016-10-31 22:37:14 +02:00
|
|
|
if (has_edp_a(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, DP_A, PORT_A);
|
2010-07-16 14:46:29 -04:00
|
|
|
|
2013-02-19 16:21:46 -03:00
|
|
|
if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) {
|
2010-03-30 15:11:33 +08:00
|
|
|
/* PCH SDVOB multiplex with HDMIB */
|
2016-11-23 16:21:44 +02:00
|
|
|
found = intel_sdvo_init(dev_priv, PCH_SDVOB, PORT_B);
|
2009-06-05 15:38:43 +08:00
|
|
|
if (!found)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, PCH_HDMIB, PORT_B);
|
2009-07-24 01:00:31 +08:00
|
|
|
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, PCH_DP_B, PORT_B);
|
2009-06-05 15:38:43 +08:00
|
|
|
}
|
|
|
|
|
|
2013-02-19 16:21:46 -03:00
|
|
|
if (I915_READ(PCH_HDMIC) & SDVO_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, PCH_HDMIC, PORT_C);
|
2009-06-05 15:38:43 +08:00
|
|
|
|
2013-02-19 16:21:46 -03:00
|
|
|
if (!dpd_is_edp && I915_READ(PCH_HDMID) & SDVO_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, PCH_HDMID, PORT_D);
|
2009-06-05 15:38:43 +08:00
|
|
|
|
2009-07-24 01:00:31 +08:00
|
|
|
if (I915_READ(PCH_DP_C) & DP_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, PCH_DP_C, PORT_C);
|
2009-07-24 01:00:31 +08:00
|
|
|
|
2012-10-27 15:52:05 +02:00
|
|
|
if (I915_READ(PCH_DP_D) & DP_DETECTED)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, PCH_DP_D, PORT_D);
|
2016-10-14 10:13:44 +01:00
|
|
|
} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
|
2016-06-03 12:17:43 +03:00
|
|
|
bool has_edp, has_port;
|
2016-06-01 08:27:50 +01:00
|
|
|
|
2014-10-09 19:37:15 +03:00
|
|
|
/*
|
|
|
|
|
* The DP_DETECTED bit is the latched state of the DDC
|
|
|
|
|
* SDA pin at boot. However since eDP doesn't require DDC
|
|
|
|
|
* (no way to plug in a DP->HDMI dongle) the DDC pins for
|
|
|
|
|
* eDP ports may have been muxed to an alternate function.
|
|
|
|
|
* Thus we can't rely on the DP_DETECTED bit alone to detect
|
|
|
|
|
* eDP ports. Consult the VBT as well as DP_DETECTED to
|
|
|
|
|
* detect eDP ports.
|
2016-06-03 12:17:43 +03:00
|
|
|
*
|
|
|
|
|
* Sadly the straps seem to be missing sometimes even for HDMI
|
|
|
|
|
* ports (eg. on Voyo V3 - CHT x7-Z8700), so check both strap
|
|
|
|
|
* and VBT for the presence of the port. Additionally we can't
|
|
|
|
|
* trust the port type the VBT declares as we've seen at least
|
|
|
|
|
* HDMI ports that the VBT claim are DP or eDP.
|
2014-10-09 19:37:15 +03:00
|
|
|
*/
|
2017-08-18 12:30:19 +03:00
|
|
|
has_edp = intel_dp_is_port_edp(dev_priv, PORT_B);
|
2016-06-03 12:17:43 +03:00
|
|
|
has_port = intel_bios_is_port_present(dev_priv, PORT_B);
|
|
|
|
|
if (I915_READ(VLV_DP_B) & DP_DETECTED || has_port)
|
2016-11-23 16:21:44 +02:00
|
|
|
has_edp &= intel_dp_init(dev_priv, VLV_DP_B, PORT_B);
|
2016-06-03 12:17:43 +03:00
|
|
|
if ((I915_READ(VLV_HDMIB) & SDVO_DETECTED || has_port) && !has_edp)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, VLV_HDMIB, PORT_B);
|
drm/i915: preserve dispaly init order on ByT
This patch changes HDMI port registration order for the BayTrail platform.
The story is that in kernel version 3.11 i915 supported only one HDMI port -
the HDMIB port. So this port ended up being HDMI-1 in user-space.
But commit '6f6005a drm/i915: expose HDMI connectors on port C on BYT'
introduced HDMIC port support. And added HDMIC registration prior to HDMIB,
so HDMIB became HDMI-2 and HDMIC became HDMI-1.
Well, this is fine as far as the kernel is concerned. i915 does not give any
guarantees to the numbering, and has never given them.
However, this breaks wayland setup in Tizen IVI. We have only one single HDMI
port on our hardware, and it is connected to HDMIB. Our configuration relies on
the fact that it is HDMI-1.
Well, certainly this is user-space problem which was exposed with Jesse's
patch. However, there is a reason why we have to do this assumption - we use
touchscreen monitors and we have to associate event devices with the monitors,
and this is not easy to do dynamically, so we just have a static setup.
Anyway, while the user-space setup will have to be fixed regardless, let's
chane the HDMI port registration order so that HDMIB stays HDMI-1, just like it
was in 3.11. Simply because there is no strong reason for changing the order in
the kernel, and it'll help setups like ours in sense that we'll have more time
for fixing the issue properly.
Also amend the commentary which looks a bit out-of-date.
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
[danvet: Drop the commment, SDVOC is gone and we have a proper HDMIC
define now.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-10-16 18:10:41 +03:00
|
|
|
|
2017-08-18 12:30:19 +03:00
|
|
|
has_edp = intel_dp_is_port_edp(dev_priv, PORT_C);
|
2016-06-03 12:17:43 +03:00
|
|
|
has_port = intel_bios_is_port_present(dev_priv, PORT_C);
|
|
|
|
|
if (I915_READ(VLV_DP_C) & DP_DETECTED || has_port)
|
2016-11-23 16:21:44 +02:00
|
|
|
has_edp &= intel_dp_init(dev_priv, VLV_DP_C, PORT_C);
|
2016-06-03 12:17:43 +03:00
|
|
|
if ((I915_READ(VLV_HDMIC) & SDVO_DETECTED || has_port) && !has_edp)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, VLV_HDMIC, PORT_C);
|
2012-09-27 19:13:07 +05:30
|
|
|
|
2016-10-14 10:13:44 +01:00
|
|
|
if (IS_CHERRYVIEW(dev_priv)) {
|
2016-06-03 12:17:43 +03:00
|
|
|
/*
|
|
|
|
|
* eDP not supported on port D,
|
|
|
|
|
* so no need to worry about it
|
|
|
|
|
*/
|
|
|
|
|
has_port = intel_bios_is_port_present(dev_priv, PORT_D);
|
|
|
|
|
if (I915_READ(CHV_DP_D) & DP_DETECTED || has_port)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, CHV_DP_D, PORT_D);
|
2016-06-03 12:17:43 +03:00
|
|
|
if (I915_READ(CHV_HDMID) & SDVO_DETECTED || has_port)
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, CHV_HDMID, PORT_D);
|
2014-04-09 13:28:56 +03:00
|
|
|
}
|
|
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dsi_init(dev_priv);
|
2016-10-13 11:03:10 +01:00
|
|
|
} else if (!IS_GEN2(dev_priv) && !IS_PINEVIEW(dev_priv)) {
|
2009-08-24 13:50:23 +08:00
|
|
|
bool found = false;
|
2009-01-02 13:33:00 -08:00
|
|
|
|
drm/i915: clarify confusion between SDVO and HDMI registers
Some HDMI registers can be used for SDVO, so saying "HDMIB" should be
the same as saying "SDVOB" for a given HW generation. This was not
true and led to confusions and even a regression.
Previously we had:
- SDVO{B,C} defined as the Gen3+ registers
- HDMI{B,C,D} and PCH_SDVOB defined as the PCH registers
But now:
- SDVO{B,C} became GEN3_SDVO{B,C} on SDVO code
- SDVO{B,C} became GEN4_HDMI{B,C} on HDMI code
- HDMI{B,C,D} became PCH_HDMI{B,C,D}
- PCH_SDVOB is still the same thing
v2: Rebase (v1 was sent in May 2012).
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-18 19:00:27 -03:00
|
|
|
if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
|
2009-12-11 11:07:17 -08:00
|
|
|
DRM_DEBUG_KMS("probing SDVOB\n");
|
2016-11-23 16:21:44 +02:00
|
|
|
found = intel_sdvo_init(dev_priv, GEN3_SDVOB, PORT_B);
|
2016-10-13 11:03:06 +01:00
|
|
|
if (!found && IS_G4X(dev_priv)) {
|
2009-12-11 11:07:17 -08:00
|
|
|
DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, GEN4_HDMIB, PORT_B);
|
2009-12-11 11:07:17 -08:00
|
|
|
}
|
2009-08-24 13:50:23 +08:00
|
|
|
|
2016-10-13 11:03:06 +01:00
|
|
|
if (!found && IS_G4X(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, DP_B, PORT_B);
|
2009-01-22 13:01:02 -08:00
|
|
|
}
|
2009-03-13 15:42:14 -04:00
|
|
|
|
|
|
|
|
/* Before G4X SDVOC doesn't have its own detect register */
|
|
|
|
|
|
drm/i915: clarify confusion between SDVO and HDMI registers
Some HDMI registers can be used for SDVO, so saying "HDMIB" should be
the same as saying "SDVOB" for a given HW generation. This was not
true and led to confusions and even a regression.
Previously we had:
- SDVO{B,C} defined as the Gen3+ registers
- HDMI{B,C,D} and PCH_SDVOB defined as the PCH registers
But now:
- SDVO{B,C} became GEN3_SDVO{B,C} on SDVO code
- SDVO{B,C} became GEN4_HDMI{B,C} on HDMI code
- HDMI{B,C,D} became PCH_HDMI{B,C,D}
- PCH_SDVOB is still the same thing
v2: Rebase (v1 was sent in May 2012).
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-18 19:00:27 -03:00
|
|
|
if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
|
2009-12-11 11:07:17 -08:00
|
|
|
DRM_DEBUG_KMS("probing SDVOC\n");
|
2016-11-23 16:21:44 +02:00
|
|
|
found = intel_sdvo_init(dev_priv, GEN3_SDVOC, PORT_C);
|
2009-12-11 11:07:17 -08:00
|
|
|
}
|
2009-08-24 13:50:23 +08:00
|
|
|
|
drm/i915: clarify confusion between SDVO and HDMI registers
Some HDMI registers can be used for SDVO, so saying "HDMIB" should be
the same as saying "SDVOB" for a given HW generation. This was not
true and led to confusions and even a regression.
Previously we had:
- SDVO{B,C} defined as the Gen3+ registers
- HDMI{B,C,D} and PCH_SDVOB defined as the PCH registers
But now:
- SDVO{B,C} became GEN3_SDVO{B,C} on SDVO code
- SDVO{B,C} became GEN4_HDMI{B,C} on HDMI code
- HDMI{B,C,D} became PCH_HDMI{B,C,D}
- PCH_SDVOB is still the same thing
v2: Rebase (v1 was sent in May 2012).
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2013-02-18 19:00:27 -03:00
|
|
|
if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) {
|
2009-08-24 13:50:23 +08:00
|
|
|
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv)) {
|
2009-12-11 11:07:17 -08:00
|
|
|
DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_hdmi_init(dev_priv, GEN4_HDMIC, PORT_C);
|
2009-12-11 11:07:17 -08:00
|
|
|
}
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, DP_C, PORT_C);
|
2009-01-22 13:01:02 -08:00
|
|
|
}
|
2009-08-24 13:50:23 +08:00
|
|
|
|
2016-10-13 11:03:06 +01:00
|
|
|
if (IS_G4X(dev_priv) && (I915_READ(DP_D) & DP_DETECTED))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dp_init(dev_priv, DP_D, PORT_D);
|
2016-10-13 11:03:10 +01:00
|
|
|
} else if (IS_GEN2(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_dvo_init(dev_priv);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-11-07 09:29:20 +00:00
|
|
|
if (SUPPORTS_TV(dev_priv))
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_tv_init(dev_priv);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_psr_init(dev_priv);
|
2014-06-13 05:10:03 -07:00
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
for_each_intel_encoder(&dev_priv->drm, encoder) {
|
2010-09-09 15:14:28 +01:00
|
|
|
encoder->base.possible_crtcs = encoder->crtc_mask;
|
|
|
|
|
encoder->base.possible_clones =
|
2012-07-12 20:08:18 +02:00
|
|
|
intel_encoder_clones(encoder);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
2011-01-11 17:06:04 +00:00
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_init_pch_refclk(dev_priv);
|
2012-10-27 15:52:05 +02:00
|
|
|
|
2016-11-23 16:21:44 +02:00
|
|
|
drm_helper_move_panel_connectors_to_head(&dev_priv->drm);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
|
|
|
|
|
{
|
|
|
|
|
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
|
|
|
|
|
|
2014-02-10 18:00:38 +01:00
|
|
|
drm_framebuffer_cleanup(fb);
|
2017-02-16 09:46:21 +00:00
|
|
|
|
2017-03-01 15:41:28 +00:00
|
|
|
i915_gem_object_lock(intel_fb->obj);
|
|
|
|
|
WARN_ON(!intel_fb->obj->framebuffer_references--);
|
|
|
|
|
i915_gem_object_unlock(intel_fb->obj);
|
|
|
|
|
|
2016-07-20 13:31:53 +01:00
|
|
|
i915_gem_object_put(intel_fb->obj);
|
2017-02-16 09:46:21 +00:00
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
kfree(intel_fb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
|
2010-11-08 19:18:58 +00:00
|
|
|
struct drm_file *file,
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
unsigned int *handle)
|
|
|
|
|
{
|
|
|
|
|
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
|
2010-11-08 19:18:58 +00:00
|
|
|
struct drm_i915_gem_object *obj = intel_fb->obj;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2015-10-13 14:22:26 +01:00
|
|
|
if (obj->userptr.mm) {
|
|
|
|
|
DRM_DEBUG("attempting to use a userptr for a framebuffer, denied\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-08 19:18:58 +00:00
|
|
|
return drm_gem_handle_create(file, &obj->base, handle);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2015-07-08 16:22:45 -07:00
|
|
|
static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
|
|
|
|
|
struct drm_file *file,
|
|
|
|
|
unsigned flags, unsigned color,
|
|
|
|
|
struct drm_clip_rect *clips,
|
|
|
|
|
unsigned num_clips)
|
|
|
|
|
{
|
2017-02-22 11:40:46 +00:00
|
|
|
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
2015-07-08 16:22:45 -07:00
|
|
|
|
2017-02-22 11:40:46 +00:00
|
|
|
i915_gem_object_flush_if_display(obj);
|
2017-02-22 11:40:49 +00:00
|
|
|
intel_fb_obj_flush(obj, ORIGIN_DIRTYFB);
|
2015-07-08 16:22:45 -07:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
static const struct drm_framebuffer_funcs intel_fb_funcs = {
|
|
|
|
|
.destroy = intel_user_framebuffer_destroy,
|
|
|
|
|
.create_handle = intel_user_framebuffer_create_handle,
|
2015-07-08 16:22:45 -07:00
|
|
|
.dirty = intel_user_framebuffer_dirty,
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
};
|
|
|
|
|
|
2015-02-27 11:15:18 +00:00
|
|
|
static
|
2016-10-14 10:13:44 +01:00
|
|
|
u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv,
|
|
|
|
|
uint64_t fb_modifier, uint32_t pixel_format)
|
2015-02-27 11:15:18 +00:00
|
|
|
{
|
2017-02-15 10:59:18 +00:00
|
|
|
u32 gen = INTEL_GEN(dev_priv);
|
2015-02-27 11:15:18 +00:00
|
|
|
|
|
|
|
|
if (gen >= 9) {
|
2016-01-20 21:05:26 +02:00
|
|
|
int cpp = drm_format_plane_cpp(pixel_format, 0);
|
|
|
|
|
|
2015-02-27 11:15:18 +00:00
|
|
|
/* "The stride in bytes must not exceed the of the size of 8K
|
|
|
|
|
* pixels and 32K bytes."
|
|
|
|
|
*/
|
2016-01-20 21:05:26 +02:00
|
|
|
return min(8192 * cpp, 32768);
|
2017-02-08 19:53:28 +02:00
|
|
|
} else if (gen >= 5 && !HAS_GMCH_DISPLAY(dev_priv)) {
|
2015-02-27 11:15:18 +00:00
|
|
|
return 32*1024;
|
|
|
|
|
} else if (gen >= 4) {
|
|
|
|
|
if (fb_modifier == I915_FORMAT_MOD_X_TILED)
|
|
|
|
|
return 16*1024;
|
|
|
|
|
else
|
|
|
|
|
return 32*1024;
|
|
|
|
|
} else if (gen >= 3) {
|
|
|
|
|
if (fb_modifier == I915_FORMAT_MOD_X_TILED)
|
|
|
|
|
return 8*1024;
|
|
|
|
|
else
|
|
|
|
|
return 16*1024;
|
|
|
|
|
} else {
|
|
|
|
|
/* XXX DSPC is limited to 4k tiled */
|
|
|
|
|
return 8*1024;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 10:59:18 +00:00
|
|
|
static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
|
|
|
|
|
struct drm_i915_gem_object *obj,
|
|
|
|
|
struct drm_mode_fb_cmd2 *mode_cmd)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2017-02-15 10:59:18 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
2017-08-01 09:58:13 -07:00
|
|
|
struct drm_framebuffer *fb = &intel_fb->base;
|
2016-11-12 01:12:56 +00:00
|
|
|
struct drm_format_name_buf format_name;
|
2017-08-01 09:58:13 -07:00
|
|
|
u32 pitch_limit;
|
2017-03-01 15:41:28 +00:00
|
|
|
unsigned int tiling, stride;
|
2017-02-15 10:59:18 +00:00
|
|
|
int ret = -EINVAL;
|
2017-08-01 09:58:13 -07:00
|
|
|
int i;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-03-01 15:41:28 +00:00
|
|
|
i915_gem_object_lock(obj);
|
|
|
|
|
obj->framebuffer_references++;
|
|
|
|
|
tiling = i915_gem_object_get_tiling(obj);
|
|
|
|
|
stride = i915_gem_object_get_stride(obj);
|
|
|
|
|
i915_gem_object_unlock(obj);
|
2013-10-09 21:23:51 +02:00
|
|
|
|
2015-02-10 17:16:06 +00:00
|
|
|
if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
|
2016-02-11 19:16:37 +02:00
|
|
|
/*
|
|
|
|
|
* If there's a fence, enforce that
|
|
|
|
|
* the fb modifier and tiling mode match.
|
|
|
|
|
*/
|
|
|
|
|
if (tiling != I915_TILING_NONE &&
|
|
|
|
|
tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("tiling_mode doesn't match fb modifier\n");
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2015-02-10 17:16:06 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2016-02-11 19:16:37 +02:00
|
|
|
if (tiling == I915_TILING_X) {
|
2015-02-10 17:16:06 +00:00
|
|
|
mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
|
2016-02-11 19:16:37 +02:00
|
|
|
} else if (tiling == I915_TILING_Y) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("No Y tiling for legacy addfb\n");
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2015-02-10 17:16:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-27 11:15:24 +00:00
|
|
|
/* Passed in modifier sanity checking. */
|
|
|
|
|
switch (mode_cmd->modifier[0]) {
|
2017-08-01 09:58:13 -07:00
|
|
|
case I915_FORMAT_MOD_Y_TILED_CCS:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED_CCS:
|
|
|
|
|
switch (mode_cmd->pixel_format) {
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
DRM_DEBUG_KMS("RC supported only with RGB8888 formats\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
/* fall through */
|
2015-02-27 11:15:24 +00:00
|
|
|
case I915_FORMAT_MOD_Y_TILED:
|
|
|
|
|
case I915_FORMAT_MOD_Yf_TILED:
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 9) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("Unsupported tiling 0x%llx!\n",
|
|
|
|
|
mode_cmd->modifier[0]);
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2015-02-27 11:15:24 +00:00
|
|
|
}
|
2017-03-24 14:29:48 -07:00
|
|
|
case DRM_FORMAT_MOD_LINEAR:
|
2015-02-27 11:15:24 +00:00
|
|
|
case I915_FORMAT_MOD_X_TILED:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("Unsupported fb modifier 0x%llx!\n",
|
|
|
|
|
mode_cmd->modifier[0]);
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2012-12-18 22:13:14 +00:00
|
|
|
}
|
2010-08-08 12:34:44 +01:00
|
|
|
|
2016-02-11 19:16:37 +02:00
|
|
|
/*
|
|
|
|
|
* gen2/3 display engine uses the fence if present,
|
|
|
|
|
* so the tiling mode must match the fb modifier exactly.
|
|
|
|
|
*/
|
2018-02-09 21:58:46 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 4 &&
|
2016-02-11 19:16:37 +02:00
|
|
|
tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("tiling_mode must match fb modifier exactly on gen2/3\n");
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2016-02-11 19:16:37 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-14 10:13:44 +01:00
|
|
|
pitch_limit = intel_fb_pitch_limit(dev_priv, mode_cmd->modifier[0],
|
2015-02-27 11:15:18 +00:00
|
|
|
mode_cmd->pixel_format);
|
2013-06-25 17:26:45 +01:00
|
|
|
if (mode_cmd->pitches[0] > pitch_limit) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("%s pitch (%u) must be at most %d\n",
|
2017-03-24 14:29:48 -07:00
|
|
|
mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
|
2017-03-07 21:42:10 +02:00
|
|
|
"tiled" : "linear",
|
|
|
|
|
mode_cmd->pitches[0], pitch_limit);
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2012-12-18 22:13:14 +00:00
|
|
|
}
|
2012-10-31 17:50:18 +02:00
|
|
|
|
2016-02-11 19:16:37 +02:00
|
|
|
/*
|
|
|
|
|
* If there's a fence, enforce that
|
|
|
|
|
* the fb pitch and fence stride match.
|
|
|
|
|
*/
|
2017-03-07 21:42:10 +02:00
|
|
|
if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) {
|
|
|
|
|
DRM_DEBUG_KMS("pitch (%d) must match tiling stride (%d)\n",
|
|
|
|
|
mode_cmd->pitches[0], stride);
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2012-12-18 22:13:14 +00:00
|
|
|
}
|
2012-10-31 17:50:18 +02:00
|
|
|
|
2012-10-31 17:50:14 +02:00
|
|
|
/* Reject formats not supported by any plane early. */
|
2011-11-14 14:51:28 -08:00
|
|
|
switch (mode_cmd->pixel_format) {
|
2012-10-31 17:50:14 +02:00
|
|
|
case DRM_FORMAT_C8:
|
2011-11-17 18:05:13 +02:00
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
2012-10-31 17:50:14 +02:00
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_XRGB1555:
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) > 3) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("unsupported pixel format: %s\n",
|
|
|
|
|
drm_get_format_name(mode_cmd->pixel_format, &format_name));
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2012-12-18 22:13:14 +00:00
|
|
|
}
|
2012-10-31 17:50:14 +02:00
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
2016-10-14 10:13:44 +01:00
|
|
|
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
|
2016-11-16 12:32:42 +00:00
|
|
|
INTEL_GEN(dev_priv) < 9) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("unsupported pixel format: %s\n",
|
|
|
|
|
drm_get_format_name(mode_cmd->pixel_format, &format_name));
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2015-05-19 12:29:16 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
2011-11-17 18:05:13 +02:00
|
|
|
case DRM_FORMAT_XRGB2101010:
|
2012-10-31 17:50:14 +02:00
|
|
|
case DRM_FORMAT_XBGR2101010:
|
2016-11-16 12:32:42 +00:00
|
|
|
if (INTEL_GEN(dev_priv) < 4) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("unsupported pixel format: %s\n",
|
|
|
|
|
drm_get_format_name(mode_cmd->pixel_format, &format_name));
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2012-12-18 22:13:14 +00:00
|
|
|
}
|
2011-06-24 12:19:27 -07:00
|
|
|
break;
|
2015-05-15 19:06:01 +01:00
|
|
|
case DRM_FORMAT_ABGR2101010:
|
2016-10-14 10:13:44 +01:00
|
|
|
if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("unsupported pixel format: %s\n",
|
|
|
|
|
drm_get_format_name(mode_cmd->pixel_format, &format_name));
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2015-05-15 19:06:01 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2011-11-17 18:05:13 +02:00
|
|
|
case DRM_FORMAT_YUYV:
|
|
|
|
|
case DRM_FORMAT_UYVY:
|
|
|
|
|
case DRM_FORMAT_YVYU:
|
|
|
|
|
case DRM_FORMAT_VYUY:
|
2017-04-21 21:14:32 +03:00
|
|
|
if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) {
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("unsupported pixel format: %s\n",
|
|
|
|
|
drm_get_format_name(mode_cmd->pixel_format, &format_name));
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2012-12-18 22:13:14 +00:00
|
|
|
}
|
2010-08-08 12:34:44 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
2017-03-07 21:42:10 +02:00
|
|
|
DRM_DEBUG_KMS("unsupported pixel format: %s\n",
|
|
|
|
|
drm_get_format_name(mode_cmd->pixel_format, &format_name));
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2010-08-08 12:34:44 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-31 17:50:19 +02:00
|
|
|
/* FIXME need to adjust LINOFF/TILEOFF accordingly. */
|
|
|
|
|
if (mode_cmd->offsets[0] != 0)
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
2012-10-31 17:50:19 +02:00
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd);
|
2017-03-07 21:42:06 +02:00
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
for (i = 0; i < fb->format->num_planes; i++) {
|
|
|
|
|
u32 stride_alignment;
|
|
|
|
|
|
|
|
|
|
if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
|
|
|
|
|
DRM_DEBUG_KMS("bad plane %d handle\n", i);
|
2017-09-10 10:56:42 +02:00
|
|
|
goto err;
|
2017-08-01 09:58:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stride_alignment = intel_fb_stride_alignment(fb, i);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Display WA #0531: skl,bxt,kbl,glk
|
|
|
|
|
*
|
|
|
|
|
* Render decompression and plane width > 3840
|
|
|
|
|
* combined with horizontal panning requires the
|
|
|
|
|
* plane stride to be a multiple of 4. We'll just
|
|
|
|
|
* require the entire fb to accommodate that to avoid
|
|
|
|
|
* potential runtime errors at plane configuration time.
|
|
|
|
|
*/
|
|
|
|
|
if (IS_GEN9(dev_priv) && i == 0 && fb->width > 3840 &&
|
|
|
|
|
(fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
|
|
|
|
|
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS))
|
|
|
|
|
stride_alignment *= 4;
|
|
|
|
|
|
|
|
|
|
if (fb->pitches[i] & (stride_alignment - 1)) {
|
|
|
|
|
DRM_DEBUG_KMS("plane %d pitch (%d) must be at least %u byte aligned\n",
|
|
|
|
|
i, fb->pitches[i], stride_alignment);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
2017-03-07 21:42:06 +02:00
|
|
|
}
|
|
|
|
|
|
2012-12-13 23:38:38 +01:00
|
|
|
intel_fb->obj = obj;
|
|
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
ret = intel_fill_fb_info(dev_priv, fb);
|
drm/i915: Rewrite fb rotation GTT handling
Redo the fb rotation handling in order to:
- eliminate the NV12 special casing
- handle fb->offsets[] properly
- make the rotation handling easier for the plane code
To achieve these goals we reduce intel_rotation_info to only contain
(for each plane) the rotated view width,height,stride in tile units,
and the page offset into the object where the plane starts. Each plane
is handled exactly the same way, no special casing for NV12 or other
formats. We then store the computed rotation_info under
intel_framebuffer so that we don't have to recompute it again.
To handle fb->offsets[] we treat them as a linear offsets and convert
them to x/y offsets from the start of the relevant GTT mapping (either
normal or rotated). We store the x/y offsets under intel_framebuffer,
and for some extra convenience we also store the rotated pitch (ie.
tile aligned plane height). So for each plane we have the normal
x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
pitch is available already in fb->pitches[].
While we're gathering up all that extra information, we can also easily
compute the storage requirements for the framebuffer, so that we can
check that the object is big enough to hold it.
When it comes time to deal with the plane source coordinates, we first
rotate the clipped src coordinates to match the relevant GTT view
orientation, then add to them the fb x/y offsets. Next we compute
the aligned surface page offset, and as a result we're left with some
residual x/y offsets. Finally, if required by the hardware, we convert
the remaining x/y offsets into a linear offset.
For gen2/3 we simply skip computing the final page offset, and just
convert the src+fb x/y offsets directly into a linear offset since
that's what the hardware wants.
After this all platforms, incluing SKL+, compute these things in exactly
the same way (excluding alignemnt differences).
v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
plane src coordinates
Drop some spurious changes that got left behind during
development
v3: Split out more changes to prep patches (Daniel)
s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
Rename intel_surf_gtt_offset to intel_fb_gtt_offset
Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
v4: Fix alignment vs. alignment-1 when calling
_intel_compute_tile_offset() from intel_fill_fb_info()
Pass the pitch in tiles in
stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
Pass the full width/height of the rotated area to
drm_rect_rotate() for clarity
Use u32 for more offsets
v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
fb ggtt offset (Sivakumar)
v6: Rebase due to drm_plane_state src/dst rects
Cc: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1470821001-25272-2-git-send-email-ville.syrjala@linux.intel.com
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-09-15 13:16:41 +03:00
|
|
|
if (ret)
|
2017-03-01 15:41:27 +00:00
|
|
|
goto err;
|
2016-02-15 22:54:47 +02:00
|
|
|
|
2017-08-01 09:58:13 -07:00
|
|
|
ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
if (ret) {
|
|
|
|
|
DRM_ERROR("framebuffer init failed %d\n", ret);
|
2017-02-15 10:59:18 +00:00
|
|
|
goto err;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2017-02-15 10:59:18 +00:00
|
|
|
|
|
|
|
|
err:
|
2017-03-01 15:41:28 +00:00
|
|
|
i915_gem_object_lock(obj);
|
|
|
|
|
obj->framebuffer_references--;
|
|
|
|
|
i915_gem_object_unlock(obj);
|
2017-02-15 10:59:18 +00:00
|
|
|
return ret;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct drm_framebuffer *
|
|
|
|
|
intel_user_framebuffer_create(struct drm_device *dev,
|
|
|
|
|
struct drm_file *filp,
|
2015-11-11 19:11:29 +02:00
|
|
|
const struct drm_mode_fb_cmd2 *user_mode_cmd)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
drm/i915: On fb alloc failure, unref gem object where it gets refed
Currently when allocating a framebuffer fails, the gem object gets
unrefed at the bottom of the call stack in __intel_framebuffer_create,
not where it gets refed, which is in intel_framebuffer_create_for_mode
(via i915_gem_alloc_object) and in intel_user_framebuffer_create
(via drm_gem_object_lookup).
This invites mistakes: __intel_framebuffer_create is also called from
intelfb_alloc, and as discovered by Tvrtko Ursulin, a double unref
was introduced there with a8bb6818270c ("drm/i915: Fix error path leak
in fbdev fb allocation").
As suggested by Ville Syrjälä, fix the double unref and improve code
clarity by moving the unref away from __intel_framebuffer_create to
where the gem object gets refed.
Based on Tvrtko Ursulin's original v2.
v3: On fb alloc failure, unref gem object where it gets refed,
fix double unref in separate commit (Ville Syrjälä)
v4: Lock struct_mutex on unref (Chris Wilson)
v5: Rebase on drm-intel-nightly 2015y-09m-01d-09h-06m-08s UTC,
rephrase commit message (Jani Nicula)
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina]
Fixes: a8bb6818270c ("drm/i915: Fix error path leak in fbdev fb
allocation")
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/2161c5062ef5d6458f8ae14d924a26d4d1dba317.1446892879.git.lukas@wunner.de
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-04 11:50:58 +02:00
|
|
|
struct drm_framebuffer *fb;
|
2010-11-08 19:18:58 +00:00
|
|
|
struct drm_i915_gem_object *obj;
|
drm/i915: Don't clobber the addfb2 ioctl params
We try to convert the old way of of specifying fb tiling (obj->tiling)
into the new fb modifiers. We store the result in the passed in mode_cmd
structure. But that structure comes directly from the addfb2 ioctl, and
gets copied back out to userspace, which means we're clobbering the
modifiers that the user provided (all 0 since the DRM_MODE_FB_MODIFIERS
flag wasn't even set by the user). Hence if the user reuses the struct
for another addfb2, the ioctl will be rejected since it's now asking for
some modifiers w/o the flag set.
Fix the problem by making a copy of the user provided structure. We can
play any games we want with the copy.
IGT-Version: 1.12-git (x86_64) (Linux: 4.4.0-rc1-stereo+ x86_64)
...
Subtest basic-X-tiled: SUCCESS (0.001s)
Test assertion failure function pitch_tests, file kms_addfb_basic.c:167:
Failed assertion: drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &f) == 0
Last errno: 22, Invalid argument
Stack trace:
#0 [__igt_fail_assert+0x101]
#1 [pitch_tests+0x619]
#2 [__real_main426+0x2f]
#3 [main+0x23]
#4 [__libc_start_main+0xf0]
#5 [_start+0x29]
#6 [<unknown>+0x29]
Subtest framebuffer-vs-set-tiling failed.
**** DEBUG ****
Test assertion failure function pitch_tests, file kms_addfb_basic.c:167:
Failed assertion: drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &f) == 0
Last errno: 22, Invalid argument
**** END ****
Subtest framebuffer-vs-set-tiling: FAIL (0.003s)
...
IGT-Version: 1.12-git (x86_64) (Linux: 4.4.0-rc1-stereo+ x86_64)
Subtest framebuffer-vs-set-tiling: SUCCESS (0.000s)
Cc: stable@vger.kernel.org # v4.1+
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Fixes: 2a80eada326f ("drm/i915: Add fb format modifier support")
Testcase: igt/kms_addfb_basic/clobbered-modifier
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1447261890-3960-1-git-send-email-ville.syrjala@linux.intel.com
2015-11-11 19:11:28 +02:00
|
|
|
struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2016-07-20 13:31:51 +01:00
|
|
|
obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
|
|
|
|
|
if (!obj)
|
2010-08-08 13:36:38 +01:00
|
|
|
return ERR_PTR(-ENOENT);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-02-15 10:59:18 +00:00
|
|
|
fb = intel_framebuffer_create(obj, &mode_cmd);
|
drm/i915: On fb alloc failure, unref gem object where it gets refed
Currently when allocating a framebuffer fails, the gem object gets
unrefed at the bottom of the call stack in __intel_framebuffer_create,
not where it gets refed, which is in intel_framebuffer_create_for_mode
(via i915_gem_alloc_object) and in intel_user_framebuffer_create
(via drm_gem_object_lookup).
This invites mistakes: __intel_framebuffer_create is also called from
intelfb_alloc, and as discovered by Tvrtko Ursulin, a double unref
was introduced there with a8bb6818270c ("drm/i915: Fix error path leak
in fbdev fb allocation").
As suggested by Ville Syrjälä, fix the double unref and improve code
clarity by moving the unref away from __intel_framebuffer_create to
where the gem object gets refed.
Based on Tvrtko Ursulin's original v2.
v3: On fb alloc failure, unref gem object where it gets refed,
fix double unref in separate commit (Ville Syrjälä)
v4: Lock struct_mutex on unref (Chris Wilson)
v5: Rebase on drm-intel-nightly 2015y-09m-01d-09h-06m-08s UTC,
rephrase commit message (Jani Nicula)
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina]
Fixes: a8bb6818270c ("drm/i915: Fix error path leak in fbdev fb
allocation")
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/2161c5062ef5d6458f8ae14d924a26d4d1dba317.1446892879.git.lukas@wunner.de
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-04 11:50:58 +02:00
|
|
|
if (IS_ERR(fb))
|
2016-10-28 13:58:43 +01:00
|
|
|
i915_gem_object_put(obj);
|
drm/i915: On fb alloc failure, unref gem object where it gets refed
Currently when allocating a framebuffer fails, the gem object gets
unrefed at the bottom of the call stack in __intel_framebuffer_create,
not where it gets refed, which is in intel_framebuffer_create_for_mode
(via i915_gem_alloc_object) and in intel_user_framebuffer_create
(via drm_gem_object_lookup).
This invites mistakes: __intel_framebuffer_create is also called from
intelfb_alloc, and as discovered by Tvrtko Ursulin, a double unref
was introduced there with a8bb6818270c ("drm/i915: Fix error path leak
in fbdev fb allocation").
As suggested by Ville Syrjälä, fix the double unref and improve code
clarity by moving the unref away from __intel_framebuffer_create to
where the gem object gets refed.
Based on Tvrtko Ursulin's original v2.
v3: On fb alloc failure, unref gem object where it gets refed,
fix double unref in separate commit (Ville Syrjälä)
v4: Lock struct_mutex on unref (Chris Wilson)
v5: Rebase on drm-intel-nightly 2015y-09m-01d-09h-06m-08s UTC,
rephrase commit message (Jani Nicula)
Tested-by: Pierre Moreau <pierre.morrow@free.fr>
[MBP 5,3 2009 nvidia MCP79 + G96 pre-retina]
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina]
Fixes: a8bb6818270c ("drm/i915: Fix error path leak in fbdev fb
allocation")
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/2161c5062ef5d6458f8ae14d924a26d4d1dba317.1446892879.git.lukas@wunner.de
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-04 11:50:58 +02:00
|
|
|
|
|
|
|
|
return fb;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-05 14:29:39 +00:00
|
|
|
static void intel_atomic_state_free(struct drm_atomic_state *state)
|
|
|
|
|
{
|
|
|
|
|
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
|
|
|
|
|
|
|
|
|
drm_atomic_state_default_release(state);
|
|
|
|
|
|
|
|
|
|
i915_sw_fence_fini(&intel_state->commit_ready);
|
|
|
|
|
|
|
|
|
|
kfree(state);
|
|
|
|
|
}
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
static const struct drm_mode_config_funcs intel_mode_funcs = {
|
|
|
|
|
.fb_create = intel_user_framebuffer_create,
|
2017-08-01 09:58:12 -07:00
|
|
|
.get_format_info = intel_get_format_info,
|
2013-10-08 17:44:49 +02:00
|
|
|
.output_poll_changed = intel_fbdev_output_poll_changed,
|
2015-01-21 16:35:44 -08:00
|
|
|
.atomic_check = intel_atomic_check,
|
|
|
|
|
.atomic_commit = intel_atomic_commit,
|
2015-06-04 10:21:28 +02:00
|
|
|
.atomic_state_alloc = intel_atomic_state_alloc,
|
|
|
|
|
.atomic_state_clear = intel_atomic_state_clear,
|
2016-12-05 14:29:39 +00:00
|
|
|
.atomic_state_free = intel_atomic_state_free,
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
};
|
|
|
|
|
|
2016-03-16 13:38:53 +02:00
|
|
|
/**
|
|
|
|
|
* intel_init_display_hooks - initialize the display modesetting hooks
|
|
|
|
|
* @dev_priv: device private
|
|
|
|
|
*/
|
|
|
|
|
void intel_init_display_hooks(struct drm_i915_private *dev_priv)
|
2009-09-21 10:42:27 -07:00
|
|
|
{
|
2017-02-07 20:33:05 +02:00
|
|
|
intel_init_cdclk_hooks(dev_priv);
|
|
|
|
|
|
2018-02-09 21:58:46 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9) {
|
2015-01-20 12:51:51 +00:00
|
|
|
dev_priv->display.get_pipe_config = haswell_get_pipe_config;
|
2015-01-20 12:51:52 +00:00
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
skylake_get_initial_plane_config;
|
2015-01-20 12:51:51 +00:00
|
|
|
dev_priv->display.crtc_compute_clock =
|
|
|
|
|
haswell_crtc_compute_clock;
|
|
|
|
|
dev_priv->display.crtc_enable = haswell_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = haswell_crtc_disable;
|
2016-03-16 13:38:53 +02:00
|
|
|
} else if (HAS_DDI(dev_priv)) {
|
2013-03-28 10:42:00 +01:00
|
|
|
dev_priv->display.get_pipe_config = haswell_get_pipe_config;
|
2015-01-20 12:51:52 +00:00
|
|
|
dev_priv->display.get_initial_plane_config =
|
2017-11-17 21:19:13 +02:00
|
|
|
i9xx_get_initial_plane_config;
|
2014-10-29 11:32:34 +02:00
|
|
|
dev_priv->display.crtc_compute_clock =
|
|
|
|
|
haswell_crtc_compute_clock;
|
2012-10-23 18:29:51 -02:00
|
|
|
dev_priv->display.crtc_enable = haswell_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = haswell_crtc_disable;
|
2016-03-16 13:38:53 +02:00
|
|
|
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
2013-03-28 10:42:00 +01:00
|
|
|
dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
|
2015-01-20 12:51:52 +00:00
|
|
|
dev_priv->display.get_initial_plane_config =
|
2017-11-17 21:19:13 +02:00
|
|
|
i9xx_get_initial_plane_config;
|
2014-10-29 11:32:35 +02:00
|
|
|
dev_priv->display.crtc_compute_clock =
|
|
|
|
|
ironlake_crtc_compute_clock;
|
2012-06-29 22:39:33 +02:00
|
|
|
dev_priv->display.crtc_enable = ironlake_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = ironlake_crtc_disable;
|
2016-03-21 18:00:13 +02:00
|
|
|
} else if (IS_CHERRYVIEW(dev_priv)) {
|
2013-04-18 14:51:36 -07:00
|
|
|
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
2015-01-20 12:51:52 +00:00
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
i9xx_get_initial_plane_config;
|
2016-03-21 18:00:13 +02:00
|
|
|
dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock;
|
|
|
|
|
dev_priv->display.crtc_enable = valleyview_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
|
|
|
|
} else if (IS_VALLEYVIEW(dev_priv)) {
|
|
|
|
|
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
|
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
i9xx_get_initial_plane_config;
|
|
|
|
|
dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock;
|
2013-04-18 14:51:36 -07:00
|
|
|
dev_priv->display.crtc_enable = valleyview_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
2016-03-21 18:00:15 +02:00
|
|
|
} else if (IS_G4X(dev_priv)) {
|
|
|
|
|
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
|
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
i9xx_get_initial_plane_config;
|
|
|
|
|
dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock;
|
|
|
|
|
dev_priv->display.crtc_enable = i9xx_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
2016-03-21 18:00:16 +02:00
|
|
|
} else if (IS_PINEVIEW(dev_priv)) {
|
|
|
|
|
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
|
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
i9xx_get_initial_plane_config;
|
|
|
|
|
dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock;
|
|
|
|
|
dev_priv->display.crtc_enable = i9xx_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
2016-03-22 15:35:23 +02:00
|
|
|
} else if (!IS_GEN2(dev_priv)) {
|
2013-03-28 10:42:00 +01:00
|
|
|
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
2015-01-20 12:51:52 +00:00
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
i9xx_get_initial_plane_config;
|
2014-10-29 11:32:36 +02:00
|
|
|
dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
|
2012-06-29 22:39:33 +02:00
|
|
|
dev_priv->display.crtc_enable = i9xx_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
2016-03-22 15:35:23 +02:00
|
|
|
} else {
|
|
|
|
|
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
|
|
|
|
dev_priv->display.get_initial_plane_config =
|
|
|
|
|
i9xx_get_initial_plane_config;
|
|
|
|
|
dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock;
|
|
|
|
|
dev_priv->display.crtc_enable = i9xx_crtc_enable;
|
|
|
|
|
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
2011-03-30 13:01:02 -07:00
|
|
|
}
|
2009-09-21 10:42:27 -07:00
|
|
|
|
2016-03-16 13:38:53 +02:00
|
|
|
if (IS_GEN5(dev_priv)) {
|
2014-08-11 09:06:39 +05:30
|
|
|
dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
|
2016-03-16 13:38:53 +02:00
|
|
|
} else if (IS_GEN6(dev_priv)) {
|
2014-08-11 09:06:39 +05:30
|
|
|
dev_priv->display.fdi_link_train = gen6_fdi_link_train;
|
2016-03-16 13:38:53 +02:00
|
|
|
} else if (IS_IVYBRIDGE(dev_priv)) {
|
2014-08-11 09:06:39 +05:30
|
|
|
/* FIXME: detect B0+ stepping and use auto training */
|
|
|
|
|
dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
|
2016-03-16 13:38:53 +02:00
|
|
|
} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
|
2014-08-11 09:06:39 +05:30
|
|
|
dev_priv->display.fdi_link_train = hsw_fdi_link_train;
|
2016-05-11 22:44:42 +03:00
|
|
|
}
|
|
|
|
|
|
2017-09-26 14:13:46 -07:00
|
|
|
if (INTEL_GEN(dev_priv) >= 9)
|
drm/i915/skl: Update DDB values atomically with wms/plane attrs
Now that we can hook into update_crtcs and control the order in which we
update CRTCs at each modeset, we can finish the final step of fixing
Skylake's watermark handling by performing DDB updates at the same time
as plane updates and watermark updates.
The first major change in this patch is skl_update_crtcs(), which
handles ensuring that we order each CRTC update in our atomic commits
properly so that they honor the DDB flush order.
The second major change in this patch is the order in which we flush the
pipes. While the previous order may have worked, it can't be used in
this approach since it no longer will do the right thing. For example,
using the old ddb flush order:
We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
allocation looks like this:
| A | B |xxxxxxx|
Since we're performing the ddb updates after performing any CRTC
disablements in intel_atomic_commit_tail(), the space to the right of
pipe B is unallocated.
1. Flush pipes with new allocation contained into old space. None
apply, so we skip this
2. Flush pipes having their allocation reduced, but overlapping with a
previous allocation. None apply, so we also skip this
3. Flush pipes that got more space allocated. This applies to A and B,
giving us the following update order: A, B
This is wrong, since updating pipe A first will cause it to overlap with
B and potentially burst into flames. Our new order (see the code
comments for details) would update the pipes in the proper order: B, A.
As well, we calculate the order for each DDB update during the check
phase, and reference it later in the commit phase when we hit
skl_update_crtcs().
This long overdue patch fixes the rest of the underruns on Skylake.
Changes since v1:
- Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
Changes since v2:
- Use the method for updating CRTCs that Ville suggested
- In skl_update_wm(), only copy the watermarks for the crtc that was
passed to us
Changes since v3:
- Small comment fix in skl_ddb_allocation_overlaps()
Changes since v4:
- Remove the second loop in intel_update_crtcs() and use Ville's
suggestion for updating the ddb allocations in the right order
- Get rid of the second loop and just use the ddb state as it updates
to determine what order to update everything in (thanks for the
suggestion Ville)
- Simplify skl_ddb_allocation_overlaps()
- Split actual overlap checking into it's own helper
Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
[omitting CC for stable, since this patch will need to be changed for
such backports first]
Testcase: kms_cursor_legacy
Testcase: plane-all-modeset-transition
Signed-off-by: Lyude <cpaul@redhat.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
2016-08-24 07:48:10 +02:00
|
|
|
dev_priv->display.update_crtcs = skl_update_crtcs;
|
|
|
|
|
else
|
|
|
|
|
dev_priv->display.update_crtcs = intel_update_crtcs;
|
2009-09-21 10:42:27 -07:00
|
|
|
}
|
|
|
|
|
|
2011-07-12 14:56:22 -07:00
|
|
|
/*
|
|
|
|
|
* Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
|
|
|
|
|
*/
|
|
|
|
|
static void quirk_ssc_force_disable(struct drm_device *dev)
|
|
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2011-07-12 14:56:22 -07:00
|
|
|
dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE;
|
2012-04-01 13:16:49 +02:00
|
|
|
DRM_INFO("applying lvds SSC disable quirk\n");
|
2011-07-12 14:56:22 -07:00
|
|
|
}
|
|
|
|
|
|
2012-03-15 15:56:26 +01:00
|
|
|
/*
|
2012-03-15 15:56:27 +01:00
|
|
|
* A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
|
|
|
|
|
* brightness value
|
2012-03-15 15:56:26 +01:00
|
|
|
*/
|
|
|
|
|
static void quirk_invert_brightness(struct drm_device *dev)
|
|
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2012-03-15 15:56:26 +01:00
|
|
|
dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS;
|
2012-04-01 13:16:49 +02:00
|
|
|
DRM_INFO("applying inverted panel brightness quirk\n");
|
2011-07-12 14:56:22 -07:00
|
|
|
}
|
|
|
|
|
|
2014-07-03 23:27:50 +00:00
|
|
|
/* Some VBT's incorrectly indicate no backlight is present */
|
|
|
|
|
static void quirk_backlight_present(struct drm_device *dev)
|
|
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2014-07-03 23:27:50 +00:00
|
|
|
dev_priv->quirks |= QUIRK_BACKLIGHT_PRESENT;
|
|
|
|
|
DRM_INFO("applying backlight present quirk\n");
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-30 09:33:48 -07:00
|
|
|
/* Toshiba Satellite P50-C-18C requires T12 delay to be min 800ms
|
|
|
|
|
* which is 300 ms greater than eDP spec T12 min.
|
|
|
|
|
*/
|
|
|
|
|
static void quirk_increase_t12_delay(struct drm_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
|
|
|
|
|
dev_priv->quirks |= QUIRK_INCREASE_T12_DELAY;
|
|
|
|
|
DRM_INFO("Applying T12 delay quirk\n");
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-19 13:53:12 -07:00
|
|
|
struct intel_quirk {
|
|
|
|
|
int device;
|
|
|
|
|
int subsystem_vendor;
|
|
|
|
|
int subsystem_device;
|
|
|
|
|
void (*hook)(struct drm_device *dev);
|
|
|
|
|
};
|
|
|
|
|
|
2012-10-14 15:46:38 +02:00
|
|
|
/* For systems that don't have a meaningful PCI subdevice/subvendor ID */
|
|
|
|
|
struct intel_dmi_quirk {
|
|
|
|
|
void (*hook)(struct drm_device *dev);
|
|
|
|
|
const struct dmi_system_id (*dmi_id_list)[];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int intel_dmi_reverse_brightness(const struct dmi_system_id *id)
|
|
|
|
|
{
|
|
|
|
|
DRM_INFO("Backlight polarity reversed on %s\n", id->ident);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct intel_dmi_quirk intel_dmi_quirks[] = {
|
|
|
|
|
{
|
|
|
|
|
.dmi_id_list = &(const struct dmi_system_id[]) {
|
|
|
|
|
{
|
|
|
|
|
.callback = intel_dmi_reverse_brightness,
|
|
|
|
|
.ident = "NCR Corporation",
|
|
|
|
|
.matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"),
|
|
|
|
|
DMI_MATCH(DMI_PRODUCT_NAME, ""),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{ } /* terminating entry */
|
|
|
|
|
},
|
|
|
|
|
.hook = quirk_invert_brightness,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2012-04-16 14:07:40 -07:00
|
|
|
static struct intel_quirk intel_quirks[] = {
|
2011-07-12 14:56:22 -07:00
|
|
|
/* Lenovo U160 cannot use SSC on LVDS */
|
|
|
|
|
{ 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
|
2011-07-28 18:52:06 +02:00
|
|
|
|
|
|
|
|
/* Sony Vaio Y cannot use SSC on LVDS */
|
|
|
|
|
{ 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
|
2012-03-15 15:56:27 +01:00
|
|
|
|
2013-12-28 21:00:39 +01:00
|
|
|
/* Acer Aspire 5734Z must invert backlight brightness */
|
|
|
|
|
{ 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
|
|
|
|
|
|
|
|
|
|
/* Acer/eMachines G725 */
|
|
|
|
|
{ 0x2a42, 0x1025, 0x0210, quirk_invert_brightness },
|
|
|
|
|
|
|
|
|
|
/* Acer/eMachines e725 */
|
|
|
|
|
{ 0x2a42, 0x1025, 0x0212, quirk_invert_brightness },
|
|
|
|
|
|
|
|
|
|
/* Acer/Packard Bell NCL20 */
|
|
|
|
|
{ 0x2a42, 0x1025, 0x034b, quirk_invert_brightness },
|
|
|
|
|
|
|
|
|
|
/* Acer Aspire 4736Z */
|
|
|
|
|
{ 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
|
2014-01-13 17:30:34 +02:00
|
|
|
|
|
|
|
|
/* Acer Aspire 5336 */
|
|
|
|
|
{ 0x2a42, 0x1025, 0x048a, quirk_invert_brightness },
|
2014-07-03 23:27:51 +00:00
|
|
|
|
|
|
|
|
/* Acer C720 and C720P Chromebooks (Celeron 2955U) have backlights */
|
|
|
|
|
{ 0x0a06, 0x1025, 0x0a11, quirk_backlight_present },
|
2014-07-03 23:27:52 +00:00
|
|
|
|
2014-08-21 16:08:02 +00:00
|
|
|
/* Acer C720 Chromebook (Core i3 4005U) */
|
|
|
|
|
{ 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
|
|
|
|
|
|
2014-10-28 20:25:53 +01:00
|
|
|
/* Apple Macbook 2,1 (Core 2 T7400) */
|
|
|
|
|
{ 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
|
|
|
|
|
|
2015-11-05 11:49:59 +02:00
|
|
|
/* Apple Macbook 4,1 */
|
|
|
|
|
{ 0x2a02, 0x106b, 0x00a1, quirk_backlight_present },
|
|
|
|
|
|
2014-07-03 23:27:52 +00:00
|
|
|
/* Toshiba CB35 Chromebook (Celeron 2955U) */
|
|
|
|
|
{ 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
|
2014-07-11 22:16:30 +00:00
|
|
|
|
|
|
|
|
/* HP Chromebook 14 (Celeron 2955U) */
|
|
|
|
|
{ 0x0a06, 0x103c, 0x21ed, quirk_backlight_present },
|
2015-02-19 10:53:39 +02:00
|
|
|
|
|
|
|
|
/* Dell Chromebook 11 */
|
|
|
|
|
{ 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
|
2015-10-30 14:50:24 +02:00
|
|
|
|
|
|
|
|
/* Dell Chromebook 11 (2015 version) */
|
|
|
|
|
{ 0x0a16, 0x1028, 0x0a35, quirk_backlight_present },
|
2017-06-30 09:33:48 -07:00
|
|
|
|
|
|
|
|
/* Toshiba Satellite P50-C-18C */
|
|
|
|
|
{ 0x191B, 0x1179, 0xF840, quirk_increase_t12_delay },
|
2010-07-19 13:53:12 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void intel_init_quirks(struct drm_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct pci_dev *d = dev->pdev;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) {
|
|
|
|
|
struct intel_quirk *q = &intel_quirks[i];
|
|
|
|
|
|
|
|
|
|
if (d->device == q->device &&
|
|
|
|
|
(d->subsystem_vendor == q->subsystem_vendor ||
|
|
|
|
|
q->subsystem_vendor == PCI_ANY_ID) &&
|
|
|
|
|
(d->subsystem_device == q->subsystem_device ||
|
|
|
|
|
q->subsystem_device == PCI_ANY_ID))
|
|
|
|
|
q->hook(dev);
|
|
|
|
|
}
|
2012-10-14 15:46:38 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) {
|
|
|
|
|
if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0)
|
|
|
|
|
intel_dmi_quirks[i].hook(dev);
|
|
|
|
|
}
|
2010-07-19 13:53:12 -07:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 15:11:26 -07:00
|
|
|
/* Disable the VGA plane that we never use */
|
2016-11-16 08:55:39 +00:00
|
|
|
static void i915_disable_vga(struct drm_i915_private *dev_priv)
|
2010-08-13 15:11:26 -07:00
|
|
|
{
|
2016-08-22 13:32:44 +03:00
|
|
|
struct pci_dev *pdev = dev_priv->drm.pdev;
|
2010-08-13 15:11:26 -07:00
|
|
|
u8 sr1;
|
2016-10-14 10:13:44 +01:00
|
|
|
i915_reg_t vga_reg = i915_vgacntrl_reg(dev_priv);
|
2010-08-13 15:11:26 -07:00
|
|
|
|
2014-01-22 21:32:38 +02:00
|
|
|
/* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
|
2016-08-22 13:32:44 +03:00
|
|
|
vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
|
2012-04-06 11:46:27 -07:00
|
|
|
outb(SR01, VGA_SR_INDEX);
|
2010-08-13 15:11:26 -07:00
|
|
|
sr1 = inb(VGA_SR_DATA);
|
|
|
|
|
outb(sr1 | 1<<5, VGA_SR_DATA);
|
2016-08-22 13:32:44 +03:00
|
|
|
vga_put(pdev, VGA_RSRC_LEGACY_IO);
|
2010-08-13 15:11:26 -07:00
|
|
|
udelay(300);
|
|
|
|
|
|
2014-12-16 18:38:37 +02:00
|
|
|
I915_WRITE(vga_reg, VGA_DISP_DISABLE);
|
2010-08-13 15:11:26 -07:00
|
|
|
POSTING_READ(vga_reg);
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-10 15:50:11 +02:00
|
|
|
void intel_modeset_init_hw(struct drm_device *dev)
|
|
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2015-12-03 14:31:06 +01:00
|
|
|
|
2016-10-31 22:37:12 +02:00
|
|
|
intel_update_cdclk(dev_priv);
|
2017-10-24 12:52:16 +03:00
|
|
|
intel_dump_cdclk_state(&dev_priv->cdclk.hw, "Current CDCLK");
|
2017-01-20 20:21:59 +02:00
|
|
|
dev_priv->cdclk.logical = dev_priv->cdclk.actual = dev_priv->cdclk.hw;
|
2012-04-10 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-03 11:37:41 -08:00
|
|
|
/*
|
|
|
|
|
* Calculate what we think the watermarks should be for the state we've read
|
|
|
|
|
* out of the hardware and then immediately program those watermarks so that
|
|
|
|
|
* we ensure the hardware settings match our internal state.
|
|
|
|
|
*
|
|
|
|
|
* We can calculate what we think WM's should be by creating a duplicate of the
|
|
|
|
|
* current state (which was constructed during hardware readout) and running it
|
|
|
|
|
* through the atomic check code to calculate new watermark values in the
|
|
|
|
|
* state object.
|
|
|
|
|
*/
|
|
|
|
|
static void sanitize_watermarks(struct drm_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct drm_atomic_state *state;
|
2016-11-08 13:55:32 +01:00
|
|
|
struct intel_atomic_state *intel_state;
|
2015-12-03 11:37:41 -08:00
|
|
|
struct drm_crtc *crtc;
|
|
|
|
|
struct drm_crtc_state *cstate;
|
|
|
|
|
struct drm_modeset_acquire_ctx ctx;
|
|
|
|
|
int ret;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Only supported on platforms that use atomic watermark design */
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
if (!dev_priv->display.optimize_watermarks)
|
2015-12-03 11:37:41 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We need to hold connection_mutex before calling duplicate_state so
|
|
|
|
|
* that the connector loop is protected.
|
|
|
|
|
*/
|
|
|
|
|
drm_modeset_acquire_init(&ctx, 0);
|
|
|
|
|
retry:
|
2016-01-12 07:13:37 -08:00
|
|
|
ret = drm_modeset_lock_all_ctx(dev, &ctx);
|
2015-12-03 11:37:41 -08:00
|
|
|
if (ret == -EDEADLK) {
|
|
|
|
|
drm_modeset_backoff(&ctx);
|
|
|
|
|
goto retry;
|
|
|
|
|
} else if (WARN_ON(ret)) {
|
2016-01-12 07:13:37 -08:00
|
|
|
goto fail;
|
2015-12-03 11:37:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = drm_atomic_helper_duplicate_state(dev, &ctx);
|
|
|
|
|
if (WARN_ON(IS_ERR(state)))
|
2016-01-12 07:13:37 -08:00
|
|
|
goto fail;
|
2015-12-03 11:37:41 -08:00
|
|
|
|
2016-11-08 13:55:32 +01:00
|
|
|
intel_state = to_intel_atomic_state(state);
|
|
|
|
|
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
/*
|
|
|
|
|
* Hardware readout is the only time we don't want to calculate
|
|
|
|
|
* intermediate watermarks (since we don't trust the current
|
|
|
|
|
* watermarks).
|
|
|
|
|
*/
|
2017-03-02 19:15:02 +02:00
|
|
|
if (!HAS_GMCH_DISPLAY(dev_priv))
|
|
|
|
|
intel_state->skip_intermediate_wm = true;
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
|
2015-12-03 11:37:41 -08:00
|
|
|
ret = intel_atomic_check(dev, state);
|
|
|
|
|
if (ret) {
|
|
|
|
|
/*
|
|
|
|
|
* If we fail here, it means that the hardware appears to be
|
|
|
|
|
* programmed in a way that shouldn't be possible, given our
|
|
|
|
|
* understanding of watermark requirements. This might mean a
|
|
|
|
|
* mistake in the hardware readout code or a mistake in the
|
|
|
|
|
* watermark calculations for a given platform. Raise a WARN
|
|
|
|
|
* so that this is noticeable.
|
|
|
|
|
*
|
|
|
|
|
* If this actually happens, we'll have to just leave the
|
|
|
|
|
* BIOS-programmed watermarks untouched and hope for the best.
|
|
|
|
|
*/
|
|
|
|
|
WARN(true, "Could not determine valid watermarks for inherited state\n");
|
2016-10-18 17:16:23 +02:00
|
|
|
goto put_state;
|
2015-12-03 11:37:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write calculated watermark values back */
|
2017-03-09 15:52:04 +01:00
|
|
|
for_each_new_crtc_in_state(state, crtc, cstate, i) {
|
2015-12-03 11:37:41 -08:00
|
|
|
struct intel_crtc_state *cs = to_intel_crtc_state(cstate);
|
|
|
|
|
|
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a
set of intermediate watermark values at atomic check time. These
intermediate watermarks are a combination of the watermarks for the old
state and the new state; they should satisfy the requirements of both
states which means they can be programmed immediately when we commit the
atomic state (without waiting for a vblank). Once the vblank does
happen, we can then re-program watermarks to the more optimal final
value.
v2: Significant rebasing/rewriting.
v3:
- Move 'need_postvbl_update' flag to CRTC state (Daniel)
- Don't forget to check intermediate watermark values for validity
(Maarten)
- Don't due async watermark optimization; just do it at the end of the
atomic transaction, after waiting for vblanks. We do want it to be
async eventually, but adding that now will cause more trouble for
Maarten's in-progress work. (Maarten)
- Don't allocate space in crtc_state for intermediate watermarks on
platforms that don't need it (gen9+).
- Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit
now that ilk_update_wm is gone.
v4:
- Add a wm_mutex to cover updates to intel_crtc->active and the
need_postvbl_update flag. Since we don't have async yet it isn't
terribly important yet, but might as well add it now.
- Change interface to program watermarks. Platforms will now expose
.initial_watermarks() and .optimize_watermarks() functions to do
watermark programming. These should lock wm_mutex, copy the
appropriate state values into intel_crtc->active, and then call
the internal program watermarks function.
v5:
- Skip intermediate watermark calculation/check during initial hardware
readout since we don't trust the existing HW values (and don't have
valid values of our own yet).
- Don't try to call .optimize_watermarks() on platforms that don't have
atomic watermarks yet. (Maarten)
v6:
- Rebase
v7:
- Further rebase
v8:
- A few minor indentation and line length fixes
v9:
- Yet another rebase since Maarten's patches reworked a bunch of the
code (wm_pre, wm_post, etc.) that this was previously based on.
v10:
- Move wm_mutex to dev_priv to protect against racing commits against
disjoint CRTC sets. (Maarten)
- Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten)
v11:
- Now that we've moved to atomic watermark updates, make sure we call
the proper function to program watermarks in
{ironlake,haswell}_crtc_enable(); the failure to do so on the
previous patch iteration led to us not actually programming the
watermarks before turning on the CRTC, which was the cause of the
underruns that the CI system was seeing.
- Fix inverted logic for determining when to optimize watermarks. We
were needlessly optimizing when the intermediate/optimal values were
the same (harmless), but not actually optimizing when they differed
(also harmless, but wasteful from a power/bandwidth perspective).
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
2016-02-23 17:20:13 -08:00
|
|
|
cs->wm.need_postvbl_update = true;
|
2016-11-08 13:55:32 +01:00
|
|
|
dev_priv->display.optimize_watermarks(intel_state, cs);
|
2017-11-10 12:34:53 +01:00
|
|
|
|
|
|
|
|
to_intel_crtc_state(crtc->state)->wm = cs->wm;
|
2015-12-03 11:37:41 -08:00
|
|
|
}
|
|
|
|
|
|
2016-10-18 17:16:23 +02:00
|
|
|
put_state:
|
2016-10-14 13:18:18 +01:00
|
|
|
drm_atomic_state_put(state);
|
2016-01-12 07:13:37 -08:00
|
|
|
fail:
|
2015-12-03 11:37:41 -08:00
|
|
|
drm_modeset_drop_locks(&ctx);
|
|
|
|
|
drm_modeset_acquire_fini(&ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-05 13:49:05 +00:00
|
|
|
static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
if (IS_GEN5(dev_priv)) {
|
|
|
|
|
u32 fdi_pll_clk =
|
|
|
|
|
I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK;
|
|
|
|
|
|
|
|
|
|
dev_priv->fdi_pll_freq = (fdi_pll_clk + 2) * 10000;
|
|
|
|
|
} else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) {
|
|
|
|
|
dev_priv->fdi_pll_freq = 270000;
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_DRIVER("FDI PLL freq=%d\n", dev_priv->fdi_pll_freq);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-25 18:58:02 +03:00
|
|
|
int intel_modeset_init(struct drm_device *dev)
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
{
|
2016-03-30 16:57:10 +03:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
2014-03-03 17:31:44 +00:00
|
|
|
enum pipe pipe;
|
2014-03-07 08:57:48 -08:00
|
|
|
struct intel_crtc *crtc;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-11-13 15:36:22 +02:00
|
|
|
dev_priv->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0);
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
drm_mode_config_init(dev);
|
|
|
|
|
|
|
|
|
|
dev->mode_config.min_width = 0;
|
|
|
|
|
dev->mode_config.min_height = 0;
|
|
|
|
|
|
2011-09-29 16:20:42 +01:00
|
|
|
dev->mode_config.preferred_depth = 24;
|
|
|
|
|
dev->mode_config.prefer_shadow = 1;
|
|
|
|
|
|
2015-02-10 17:16:16 +00:00
|
|
|
dev->mode_config.allow_fb_modifiers = true;
|
|
|
|
|
|
2012-05-17 13:27:23 +02:00
|
|
|
dev->mode_config.funcs = &intel_mode_funcs;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2017-04-07 01:23:45 +02:00
|
|
|
init_llist_head(&dev_priv->atomic_helper.free_list);
|
2017-01-23 21:29:39 +00:00
|
|
|
INIT_WORK(&dev_priv->atomic_helper.free_work,
|
2017-02-02 20:47:41 +00:00
|
|
|
intel_atomic_helper_free_state_worker);
|
2017-01-23 21:29:39 +00:00
|
|
|
|
2010-07-19 13:53:12 -07:00
|
|
|
intel_init_quirks(dev);
|
|
|
|
|
|
2016-10-31 22:37:25 +02:00
|
|
|
intel_init_pm(dev_priv);
|
2012-04-18 15:29:26 -03:00
|
|
|
|
2016-11-09 11:30:45 +00:00
|
|
|
if (INTEL_INFO(dev_priv)->num_pipes == 0)
|
2016-10-25 18:58:02 +03:00
|
|
|
return 0;
|
2013-04-05 13:12:39 -07:00
|
|
|
|
drm/i915: Preserve SSC earlier
Commit 92122789b2d6 ("drm/i915: preserve SSC if previously set v3")
added code to intel_modeset_gem_init to override the SSC status read
from VBT with the SSC status set by BIOS.
However, intel_modeset_gem_init is invoked *after* intel_modeset_init,
which calls intel_setup_outputs, which *modifies* SSC status by way of
intel_init_pch_refclk. So unlike advertised, intel_modeset_gem_init
doesn't preserve the SSC status set by BIOS but whatever
intel_init_pch_refclk decided on.
This is a problem on dual gpu laptops such as the MacBook Pro which
require either a handler to switch DDC lines, or the discrete gpu
to proxy DDC/AUX communication: Both the handler and the discrete
gpu may initialize after the i915 driver, and consequently, an LVDS
connector may initially seem disconnected and the SSC therefore
is disabled by intel_init_pch_refclk, but on reprobe the connector
may turn out to be connected and the SSC must then be enabled.
Due to 92122789b2d6 however, the SSC is not enabled on reprobe since
it is assumed BIOS disabled it while in fact it was disabled by
intel_init_pch_refclk.
Also, because the SSC status is preserved so late, the preserved value
only ever gets used on resume but not on panel initialization:
intel_modeset_init calls intel_init_display which indirectly calls
intel_panel_use_ssc via multiple subroutines, *before* the BIOS value
overrides the VBT value in intel_modeset_gem_init (intel_panel_use_ssc
is the sole user of dev_priv->vbt.lvds_use_ssc).
Fix this by moving the code introduced by 92122789b2d6 from
intel_modeset_gem_init to intel_modeset_init before the invocation
of intel_setup_outputs and intel_init_display.
Add a DRM_DEBUG_KMS as suggested way back by Jani:
http://lists.freedesktop.org/archives/intel-gfx/2014-June/046666.html
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
Fixes: 92122789b2d6 ("drm/i915: preserve SSC if previously set v3")
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-15 13:57:35 +02:00
|
|
|
/*
|
|
|
|
|
* There may be no VBT; and if the BIOS enabled SSC we can
|
|
|
|
|
* just keep using it to avoid unnecessary flicker. Whereas if the
|
|
|
|
|
* BIOS isn't using it, don't assume it will work even if the VBT
|
|
|
|
|
* indicates as much.
|
|
|
|
|
*/
|
2016-10-13 11:02:53 +01:00
|
|
|
if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) {
|
drm/i915: Preserve SSC earlier
Commit 92122789b2d6 ("drm/i915: preserve SSC if previously set v3")
added code to intel_modeset_gem_init to override the SSC status read
from VBT with the SSC status set by BIOS.
However, intel_modeset_gem_init is invoked *after* intel_modeset_init,
which calls intel_setup_outputs, which *modifies* SSC status by way of
intel_init_pch_refclk. So unlike advertised, intel_modeset_gem_init
doesn't preserve the SSC status set by BIOS but whatever
intel_init_pch_refclk decided on.
This is a problem on dual gpu laptops such as the MacBook Pro which
require either a handler to switch DDC lines, or the discrete gpu
to proxy DDC/AUX communication: Both the handler and the discrete
gpu may initialize after the i915 driver, and consequently, an LVDS
connector may initially seem disconnected and the SSC therefore
is disabled by intel_init_pch_refclk, but on reprobe the connector
may turn out to be connected and the SSC must then be enabled.
Due to 92122789b2d6 however, the SSC is not enabled on reprobe since
it is assumed BIOS disabled it while in fact it was disabled by
intel_init_pch_refclk.
Also, because the SSC status is preserved so late, the preserved value
only ever gets used on resume but not on panel initialization:
intel_modeset_init calls intel_init_display which indirectly calls
intel_panel_use_ssc via multiple subroutines, *before* the BIOS value
overrides the VBT value in intel_modeset_gem_init (intel_panel_use_ssc
is the sole user of dev_priv->vbt.lvds_use_ssc).
Fix this by moving the code introduced by 92122789b2d6 from
intel_modeset_gem_init to intel_modeset_init before the invocation
of intel_setup_outputs and intel_init_display.
Add a DRM_DEBUG_KMS as suggested way back by Jani:
http://lists.freedesktop.org/archives/intel-gfx/2014-June/046666.html
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
[MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
[MBP 8,2 2011 intel SNB + amd turks pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
[MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
[MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress]
Fixes: 92122789b2d6 ("drm/i915: preserve SSC if previously set v3")
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
2015-07-15 13:57:35 +02:00
|
|
|
bool bios_lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) &
|
|
|
|
|
DREF_SSC1_ENABLE);
|
|
|
|
|
|
|
|
|
|
if (dev_priv->vbt.lvds_use_ssc != bios_lvds_use_ssc) {
|
|
|
|
|
DRM_DEBUG_KMS("SSC %sabled by BIOS, overriding VBT which says %sabled\n",
|
|
|
|
|
bios_lvds_use_ssc ? "en" : "dis",
|
|
|
|
|
dev_priv->vbt.lvds_use_ssc ? "en" : "dis");
|
|
|
|
|
dev_priv->vbt.lvds_use_ssc = bios_lvds_use_ssc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:03:10 +01:00
|
|
|
if (IS_GEN2(dev_priv)) {
|
2010-09-17 00:32:17 +01:00
|
|
|
dev->mode_config.max_width = 2048;
|
|
|
|
|
dev->mode_config.max_height = 2048;
|
2016-10-13 11:03:10 +01:00
|
|
|
} else if (IS_GEN3(dev_priv)) {
|
2009-07-12 23:53:17 -07:00
|
|
|
dev->mode_config.max_width = 4096;
|
|
|
|
|
dev->mode_config.max_height = 4096;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
} else {
|
2010-09-17 00:32:17 +01:00
|
|
|
dev->mode_config.max_width = 8192;
|
|
|
|
|
dev->mode_config.max_height = 8192;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
2014-03-28 14:17:49 +00:00
|
|
|
|
2016-11-30 17:43:04 +02:00
|
|
|
if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
|
|
|
|
|
dev->mode_config.cursor_width = IS_I845G(dev_priv) ? 64 : 512;
|
2014-08-13 11:57:05 +03:00
|
|
|
dev->mode_config.cursor_height = 1023;
|
2016-10-13 11:03:10 +01:00
|
|
|
} else if (IS_GEN2(dev_priv)) {
|
2014-03-28 14:17:49 +00:00
|
|
|
dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH;
|
|
|
|
|
dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT;
|
|
|
|
|
} else {
|
|
|
|
|
dev->mode_config.cursor_width = MAX_CURSOR_WIDTH;
|
|
|
|
|
dev->mode_config.cursor_height = MAX_CURSOR_HEIGHT;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-11 15:18:20 +00:00
|
|
|
dev->mode_config.fb_base = ggtt->gmadr.start;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2009-10-09 11:39:41 +08:00
|
|
|
DRM_DEBUG_KMS("%d display pipe%s available.\n",
|
2016-11-09 11:30:45 +00:00
|
|
|
INTEL_INFO(dev_priv)->num_pipes,
|
|
|
|
|
INTEL_INFO(dev_priv)->num_pipes > 1 ? "s" : "");
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
|
2014-08-18 13:49:10 +01:00
|
|
|
for_each_pipe(dev_priv, pipe) {
|
2016-10-25 18:58:02 +03:00
|
|
|
int ret;
|
|
|
|
|
|
2016-10-31 22:37:11 +02:00
|
|
|
ret = intel_crtc_init(dev_priv, pipe);
|
2016-10-25 18:58:02 +03:00
|
|
|
if (ret) {
|
|
|
|
|
drm_mode_config_cleanup(dev);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2013-06-05 13:34:06 +02:00
|
|
|
intel_shared_dpll_init(dev);
|
2017-11-05 13:49:05 +00:00
|
|
|
intel_update_fdi_pll_freq(dev_priv);
|
2012-04-20 17:11:53 +01:00
|
|
|
|
2017-02-20 16:04:43 +02:00
|
|
|
intel_update_czclk(dev_priv);
|
|
|
|
|
intel_modeset_init_hw(dev);
|
|
|
|
|
|
2016-05-13 23:41:27 +03:00
|
|
|
if (dev_priv->max_cdclk_freq == 0)
|
2016-10-31 22:37:12 +02:00
|
|
|
intel_update_max_cdclk(dev_priv);
|
2016-05-13 23:41:27 +03:00
|
|
|
|
2010-08-13 15:11:26 -07:00
|
|
|
/* Just disable it once at startup */
|
2016-11-16 08:55:39 +00:00
|
|
|
i915_disable_vga(dev_priv);
|
2016-11-23 16:21:44 +02:00
|
|
|
intel_setup_outputs(dev_priv);
|
2012-11-15 11:32:20 +00:00
|
|
|
|
drm: Split connection_mutex out of mode_config.mutex (v3)
After the split-out of crtc locks from the big mode_config.mutex
there's still two major areas it protects:
- Various connector probe states, like connector->status, EDID
properties, probed mode lists and similar information.
- The links from connector->encoder and encoder->crtc and other
modeset-relevant connector state (e.g. properties which control the
panel fitter).
The later is used by modeset operations. But they don't really care
about the former since it's allowed to e.g. enable a disconnected VGA
output or with a mode not in the probed list.
Thus far this hasn't been a problem, but for the atomic modeset
conversion Rob Clark needs to convert all modeset relevant locks into
w/w locks. This is required because the order of acquisition is
determined by how userspace supplies the atomic modeset data. This has
run into troubles in the detect path since the i915 load detect code
needs _both_ protections offered by the mode_config.mutex: It updates
probe state and it needs to change the modeset configuration to enable
the temporary load detect pipe.
The big deal here is that for the probe/detect users of this lock a
plain mutex fits best, but for atomic modesets we really want a w/w
mutex. To fix this lets split out a new connection_mutex lock for the
modeset relevant parts.
For simplicity I've decided to only add one additional lock for all
connector/encoder links and modeset configuration states. We have
piles of different modeset objects in addition to those (like bridges
or panels), so adding per-object locks would be much more effort.
Also, we're guaranteed (at least for now) to do a full modeset if we
need to acquire this lock. Which means that fine-grained locking is
fairly irrelevant compared to the amount of time the full modeset will
take.
I've done a full audit, and there's just a few things that justify
special focus:
- Locking in drm_sysfs.c is almost completely absent. We should
sprinkle mode_config.connection_mutex over this file a bit, but
since it already lacks mode_config.mutex this patch wont make the
situation any worse. This is material for a follow-up patch.
- omap has a omap_framebuffer_flush function which walks the
connector->encoder->crtc links and is called from many contexts.
Some look like they don't acquire mode_config.mutex, so this is
already racy. Again fixing this is material for a separate patch.
- The radeon hot_plug function to retrain DP links looks at
connector->dpms. Currently this happens without any locking, so is
already racy. I think radeon_hotplug_work_func should gain
mutex_lock/unlock calls for the mode_config.connection_mutex.
- Same applies to i915's intel_dp_hot_plug. But again, this is already
racy.
- i915 load_detect code needs to acquire this lock. Which means the
w/w dance due to Rob's work will be nicely contained to _just_ this
function.
I've added fixme comments everywhere where it looks suspicious but in
the sysfs code. After a quick irc discussion with Dave Airlie it
sounds like the lack of locking in there is due to sysfs cleanup fun
at module unload.
v1: original (only compile tested)
v2: missing mutex_init(), etc (from Rob Clark)
v3: i915 needs more care in the conversion:
- Protect the edp pp logic with the connection_mutex.
- Use connection_mutex in the backlight code due to
get_pipe_from_connector.
- Use drm_modeset_lock_all in suspend/resume paths.
- Update lock checks in the overlay code.
Cc: Alex Deucher <alexdeucher@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Rob Clark <robdclark@gmail.com>
2014-05-29 23:54:47 +02:00
|
|
|
drm_modeset_lock_all(dev);
|
2017-06-01 17:36:13 +03:00
|
|
|
intel_modeset_setup_hw_state(dev, dev->mode_config.acquire_ctx);
|
drm: Split connection_mutex out of mode_config.mutex (v3)
After the split-out of crtc locks from the big mode_config.mutex
there's still two major areas it protects:
- Various connector probe states, like connector->status, EDID
properties, probed mode lists and similar information.
- The links from connector->encoder and encoder->crtc and other
modeset-relevant connector state (e.g. properties which control the
panel fitter).
The later is used by modeset operations. But they don't really care
about the former since it's allowed to e.g. enable a disconnected VGA
output or with a mode not in the probed list.
Thus far this hasn't been a problem, but for the atomic modeset
conversion Rob Clark needs to convert all modeset relevant locks into
w/w locks. This is required because the order of acquisition is
determined by how userspace supplies the atomic modeset data. This has
run into troubles in the detect path since the i915 load detect code
needs _both_ protections offered by the mode_config.mutex: It updates
probe state and it needs to change the modeset configuration to enable
the temporary load detect pipe.
The big deal here is that for the probe/detect users of this lock a
plain mutex fits best, but for atomic modesets we really want a w/w
mutex. To fix this lets split out a new connection_mutex lock for the
modeset relevant parts.
For simplicity I've decided to only add one additional lock for all
connector/encoder links and modeset configuration states. We have
piles of different modeset objects in addition to those (like bridges
or panels), so adding per-object locks would be much more effort.
Also, we're guaranteed (at least for now) to do a full modeset if we
need to acquire this lock. Which means that fine-grained locking is
fairly irrelevant compared to the amount of time the full modeset will
take.
I've done a full audit, and there's just a few things that justify
special focus:
- Locking in drm_sysfs.c is almost completely absent. We should
sprinkle mode_config.connection_mutex over this file a bit, but
since it already lacks mode_config.mutex this patch wont make the
situation any worse. This is material for a follow-up patch.
- omap has a omap_framebuffer_flush function which walks the
connector->encoder->crtc links and is called from many contexts.
Some look like they don't acquire mode_config.mutex, so this is
already racy. Again fixing this is material for a separate patch.
- The radeon hot_plug function to retrain DP links looks at
connector->dpms. Currently this happens without any locking, so is
already racy. I think radeon_hotplug_work_func should gain
mutex_lock/unlock calls for the mode_config.connection_mutex.
- Same applies to i915's intel_dp_hot_plug. But again, this is already
racy.
- i915 load_detect code needs to acquire this lock. Which means the
w/w dance due to Rob's work will be nicely contained to _just_ this
function.
I've added fixme comments everywhere where it looks suspicious but in
the sysfs code. After a quick irc discussion with Dave Airlie it
sounds like the lack of locking in there is due to sysfs cleanup fun
at module unload.
v1: original (only compile tested)
v2: missing mutex_init(), etc (from Rob Clark)
v3: i915 needs more care in the conversion:
- Protect the edp pp logic with the connection_mutex.
- Use connection_mutex in the backlight code due to
get_pipe_from_connector.
- Use drm_modeset_lock_all in suspend/resume paths.
- Update lock checks in the overlay code.
Cc: Alex Deucher <alexdeucher@gmail.com>
Cc: Rob Clark <robdclark@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Rob Clark <robdclark@gmail.com>
2014-05-29 23:54:47 +02:00
|
|
|
drm_modeset_unlock_all(dev);
|
2014-03-07 08:57:48 -08:00
|
|
|
|
2014-05-13 23:32:22 +01:00
|
|
|
for_each_intel_crtc(dev, crtc) {
|
2015-07-14 12:33:29 +02:00
|
|
|
struct intel_initial_plane_config plane_config = {};
|
|
|
|
|
|
2014-03-07 08:57:48 -08:00
|
|
|
if (!crtc->active)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note that reserving the BIOS fb up front prevents us
|
|
|
|
|
* from stuffing other stolen allocations like the ring
|
|
|
|
|
* on top. This prevents some ugliness at boot time, and
|
|
|
|
|
* can even allow for smooth boot transitions if the BIOS
|
|
|
|
|
* fb is large enough for the active pipe configuration.
|
|
|
|
|
*/
|
2015-07-14 12:33:29 +02:00
|
|
|
dev_priv->display.get_initial_plane_config(crtc,
|
|
|
|
|
&plane_config);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the fb is shared between multiple heads, we'll
|
|
|
|
|
* just get the first one.
|
|
|
|
|
*/
|
|
|
|
|
intel_find_initial_plane_obj(crtc, &plane_config);
|
2014-03-07 08:57:48 -08:00
|
|
|
}
|
2015-12-03 11:37:41 -08:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure hardware watermarks really match the state we read out.
|
|
|
|
|
* Note that we need to do this after reconstructing the BIOS fb's
|
|
|
|
|
* since the watermark calculation done here will use pstate->fb.
|
|
|
|
|
*/
|
2017-03-02 19:15:02 +02:00
|
|
|
if (!HAS_GMCH_DISPLAY(dev_priv))
|
|
|
|
|
sanitize_watermarks(dev);
|
2016-10-25 18:58:02 +03:00
|
|
|
|
|
|
|
|
return 0;
|
2011-03-29 10:40:27 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-01 17:36:16 +03:00
|
|
|
void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|
|
|
|
{
|
2017-11-29 17:37:31 +02:00
|
|
|
struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
2017-06-01 17:36:16 +03:00
|
|
|
/* 640x480@60Hz, ~25175 kHz */
|
|
|
|
|
struct dpll clock = {
|
|
|
|
|
.m1 = 18,
|
|
|
|
|
.m2 = 7,
|
|
|
|
|
.p1 = 13,
|
|
|
|
|
.p2 = 4,
|
|
|
|
|
.n = 2,
|
|
|
|
|
};
|
|
|
|
|
u32 dpll, fp;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
WARN_ON(i9xx_calc_dpll_params(48000, &clock) != 25154);
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("enabling pipe %c due to force quirk (vco=%d dot=%d)\n",
|
|
|
|
|
pipe_name(pipe), clock.vco, clock.dot);
|
|
|
|
|
|
|
|
|
|
fp = i9xx_dpll_compute_fp(&clock);
|
|
|
|
|
dpll = (I915_READ(DPLL(pipe)) & DPLL_DVO_2X_MODE) |
|
|
|
|
|
DPLL_VGA_MODE_DIS |
|
|
|
|
|
((clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT) |
|
|
|
|
|
PLL_P2_DIVIDE_BY_4 |
|
|
|
|
|
PLL_REF_INPUT_DREFCLK |
|
|
|
|
|
DPLL_VCO_ENABLE;
|
|
|
|
|
|
|
|
|
|
I915_WRITE(FP0(pipe), fp);
|
|
|
|
|
I915_WRITE(FP1(pipe), fp);
|
|
|
|
|
|
|
|
|
|
I915_WRITE(HTOTAL(pipe), (640 - 1) | ((800 - 1) << 16));
|
|
|
|
|
I915_WRITE(HBLANK(pipe), (640 - 1) | ((800 - 1) << 16));
|
|
|
|
|
I915_WRITE(HSYNC(pipe), (656 - 1) | ((752 - 1) << 16));
|
|
|
|
|
I915_WRITE(VTOTAL(pipe), (480 - 1) | ((525 - 1) << 16));
|
|
|
|
|
I915_WRITE(VBLANK(pipe), (480 - 1) | ((525 - 1) << 16));
|
|
|
|
|
I915_WRITE(VSYNC(pipe), (490 - 1) | ((492 - 1) << 16));
|
|
|
|
|
I915_WRITE(PIPESRC(pipe), ((640 - 1) << 16) | (480 - 1));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Apparently we need to have VGA mode enabled prior to changing
|
|
|
|
|
* the P1/P2 dividers. Otherwise the DPLL will keep using the old
|
|
|
|
|
* dividers, even though the register value does change.
|
|
|
|
|
*/
|
|
|
|
|
I915_WRITE(DPLL(pipe), dpll & ~DPLL_VGA_MODE_DIS);
|
|
|
|
|
I915_WRITE(DPLL(pipe), dpll);
|
|
|
|
|
|
|
|
|
|
/* Wait for the clocks to stabilize. */
|
|
|
|
|
POSTING_READ(DPLL(pipe));
|
|
|
|
|
udelay(150);
|
|
|
|
|
|
|
|
|
|
/* The pixel multiplier can only be updated once the
|
|
|
|
|
* DPLL is enabled and the clocks are stable.
|
|
|
|
|
*
|
|
|
|
|
* So write it again.
|
|
|
|
|
*/
|
|
|
|
|
I915_WRITE(DPLL(pipe), dpll);
|
|
|
|
|
|
|
|
|
|
/* We do this three times for luck */
|
|
|
|
|
for (i = 0; i < 3 ; i++) {
|
|
|
|
|
I915_WRITE(DPLL(pipe), dpll);
|
|
|
|
|
POSTING_READ(DPLL(pipe));
|
|
|
|
|
udelay(150); /* wait for warmup */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
I915_WRITE(PIPECONF(pipe), PIPECONF_ENABLE | PIPECONF_PROGRESSIVE);
|
|
|
|
|
POSTING_READ(PIPECONF(pipe));
|
2017-11-29 17:37:31 +02:00
|
|
|
|
|
|
|
|
intel_wait_for_pipe_scanline_moving(crtc);
|
2017-06-01 17:36:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|
|
|
|
{
|
2017-11-29 17:37:30 +02:00
|
|
|
struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
|
|
|
|
|
2017-06-01 17:36:16 +03:00
|
|
|
DRM_DEBUG_KMS("disabling pipe %c due to force quirk\n",
|
|
|
|
|
pipe_name(pipe));
|
|
|
|
|
|
2017-11-29 14:54:11 +02:00
|
|
|
WARN_ON(I915_READ(DSPCNTR(PLANE_A)) & DISPLAY_PLANE_ENABLE);
|
|
|
|
|
WARN_ON(I915_READ(DSPCNTR(PLANE_B)) & DISPLAY_PLANE_ENABLE);
|
|
|
|
|
WARN_ON(I915_READ(DSPCNTR(PLANE_C)) & DISPLAY_PLANE_ENABLE);
|
|
|
|
|
WARN_ON(I915_READ(CURCNTR(PIPE_A)) & CURSOR_MODE);
|
|
|
|
|
WARN_ON(I915_READ(CURCNTR(PIPE_B)) & CURSOR_MODE);
|
2017-06-01 17:36:16 +03:00
|
|
|
|
|
|
|
|
I915_WRITE(PIPECONF(pipe), 0);
|
|
|
|
|
POSTING_READ(PIPECONF(pipe));
|
|
|
|
|
|
2017-11-29 17:37:30 +02:00
|
|
|
intel_wait_for_pipe_scanline_stopped(crtc);
|
2017-06-01 17:36:16 +03:00
|
|
|
|
|
|
|
|
I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS);
|
|
|
|
|
POSTING_READ(DPLL(pipe));
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
static bool intel_plane_mapping_ok(struct intel_crtc *crtc,
|
2017-11-17 21:19:10 +02:00
|
|
|
struct intel_plane *plane)
|
2012-10-10 23:14:00 +02:00
|
|
|
{
|
2016-11-09 11:30:45 +00:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
2017-11-17 21:19:10 +02:00
|
|
|
enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
|
|
|
|
|
u32 val = I915_READ(DSPCNTR(i9xx_plane));
|
2012-10-10 23:14:00 +02:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
return (val & DISPLAY_PLANE_ENABLE) == 0 ||
|
|
|
|
|
(val & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE(crtc->pipe);
|
|
|
|
|
}
|
2012-10-10 23:14:00 +02:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
static void
|
|
|
|
|
intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
struct intel_crtc *crtc;
|
2012-10-10 23:14:00 +02:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4)
|
|
|
|
|
return;
|
2012-10-10 23:14:00 +02:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
|
|
|
|
struct intel_plane *plane =
|
|
|
|
|
to_intel_plane(crtc->base.primary);
|
|
|
|
|
|
|
|
|
|
if (intel_plane_mapping_ok(crtc, plane))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("%s attached to the wrong pipe, disabling plane\n",
|
|
|
|
|
plane->base.name);
|
|
|
|
|
intel_plane_disable_noatomic(crtc, plane);
|
|
|
|
|
}
|
2012-10-10 23:14:00 +02:00
|
|
|
}
|
|
|
|
|
|
2015-08-26 19:39:19 +03:00
|
|
|
static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
|
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
|
|
|
|
|
for_each_encoder_on_crtc(dev, &crtc->base, encoder)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-23 16:18:07 +02:00
|
|
|
static struct intel_connector *intel_encoder_find_connector(struct intel_encoder *encoder)
|
|
|
|
|
{
|
|
|
|
|
struct drm_device *dev = encoder->base.dev;
|
|
|
|
|
struct intel_connector *connector;
|
|
|
|
|
|
|
|
|
|
for_each_connector_on_encoder(dev, &encoder->base, connector)
|
|
|
|
|
return connector;
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-05 20:00:17 +03:00
|
|
|
static bool has_pch_trancoder(struct drm_i915_private *dev_priv,
|
2017-10-10 15:55:56 +03:00
|
|
|
enum pipe pch_transcoder)
|
2016-08-05 20:00:17 +03:00
|
|
|
{
|
|
|
|
|
return HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
|
2017-10-10 15:55:56 +03:00
|
|
|
(HAS_PCH_LPT_H(dev_priv) && pch_transcoder == PIPE_A);
|
2016-08-05 20:00:17 +03:00
|
|
|
}
|
|
|
|
|
|
2017-06-01 17:36:13 +03:00
|
|
|
static void intel_sanitize_crtc(struct intel_crtc *crtc,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
{
|
|
|
|
|
struct drm_device *dev = crtc->base.dev;
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2016-03-18 17:05:42 +02:00
|
|
|
enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
|
|
|
|
/* Clear any frame start delays used for debugging left by the BIOS */
|
2017-11-15 22:04:42 +02:00
|
|
|
if (crtc->active && !transcoder_is_dsi(cpu_transcoder)) {
|
2016-03-18 17:05:42 +02:00
|
|
|
i915_reg_t reg = PIPECONF(cpu_transcoder);
|
|
|
|
|
|
|
|
|
|
I915_WRITE(reg,
|
|
|
|
|
I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
|
|
|
|
|
}
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
2014-05-20 17:20:05 +03:00
|
|
|
/* restore vblank interrupts to correct state */
|
2015-02-13 21:03:42 +01:00
|
|
|
drm_crtc_vblank_reset(&crtc->base);
|
2014-08-06 14:50:01 +03:00
|
|
|
if (crtc->active) {
|
2015-09-10 18:59:08 +03:00
|
|
|
struct intel_plane *plane;
|
|
|
|
|
|
2015-02-13 21:03:42 +01:00
|
|
|
drm_crtc_vblank_on(&crtc->base);
|
2015-09-10 18:59:08 +03:00
|
|
|
|
|
|
|
|
/* Disable everything but the primary plane */
|
|
|
|
|
for_each_intel_plane_on_crtc(dev, crtc, plane) {
|
2017-11-17 21:19:09 +02:00
|
|
|
const struct intel_plane_state *plane_state =
|
|
|
|
|
to_intel_plane_state(plane->base.state);
|
2015-09-10 18:59:08 +03:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
if (plane_state->base.visible &&
|
|
|
|
|
plane->base.type != DRM_PLANE_TYPE_PRIMARY)
|
|
|
|
|
intel_plane_disable_noatomic(crtc, plane);
|
2015-09-10 18:59:08 +03:00
|
|
|
}
|
2015-02-13 21:03:42 +01:00
|
|
|
}
|
2014-05-20 17:20:05 +03:00
|
|
|
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
/* Adjust the state of the output pipe according to whether we
|
|
|
|
|
* have active connectors/encoders. */
|
2016-03-02 15:48:01 +01:00
|
|
|
if (crtc->active && !intel_crtc_has_encoders(crtc))
|
2017-06-01 17:36:14 +03:00
|
|
|
intel_crtc_disable_noatomic(&crtc->base, ctx);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
2016-10-13 11:02:54 +01:00
|
|
|
if (crtc->active || HAS_GMCH_DISPLAY(dev_priv)) {
|
2014-03-24 00:01:41 +01:00
|
|
|
/*
|
|
|
|
|
* We start out with underrun reporting disabled to avoid races.
|
|
|
|
|
* For correct bookkeeping mark this on active crtcs.
|
|
|
|
|
*
|
2014-05-14 15:40:34 +02:00
|
|
|
* Also on gmch platforms we dont have any hardware bits to
|
|
|
|
|
* disable the underrun reporting. Which means we need to start
|
|
|
|
|
* out with underrun reporting disabled also on inactive pipes,
|
|
|
|
|
* since otherwise we'll complain about the garbage we read when
|
|
|
|
|
* e.g. coming up after runtime pm.
|
|
|
|
|
*
|
2014-03-24 00:01:41 +01:00
|
|
|
* No protection against concurrent access is required - at
|
|
|
|
|
* worst a fifo underrun happens which also sets this to false.
|
|
|
|
|
*/
|
|
|
|
|
crtc->cpu_fifo_underrun_disabled = true;
|
2016-08-05 20:00:17 +03:00
|
|
|
/*
|
|
|
|
|
* We track the PCH trancoder underrun reporting state
|
|
|
|
|
* within the crtc. With crtc for pipe A housing the underrun
|
|
|
|
|
* reporting state for PCH transcoder A, crtc for pipe B housing
|
|
|
|
|
* it for PCH transcoder B, etc. LPT-H has only PCH transcoder A,
|
|
|
|
|
* and marking underrun reporting as disabled for the non-existing
|
|
|
|
|
* PCH transcoders B and C would prevent enabling the south
|
|
|
|
|
* error interrupt (see cpt_can_enable_serr_int()).
|
|
|
|
|
*/
|
2017-10-10 15:55:56 +03:00
|
|
|
if (has_pch_trancoder(dev_priv, crtc->pipe))
|
2016-08-05 20:00:17 +03:00
|
|
|
crtc->pch_fifo_underrun_disabled = true;
|
2014-03-24 00:01:41 +01:00
|
|
|
}
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_sanitize_encoder(struct intel_encoder *encoder)
|
|
|
|
|
{
|
|
|
|
|
struct intel_connector *connector;
|
|
|
|
|
|
|
|
|
|
/* We need to check both for a crtc link (meaning that the
|
|
|
|
|
* encoder is active and trying to read from a pipe) and the
|
|
|
|
|
* pipe itself being active. */
|
|
|
|
|
bool has_active_crtc = encoder->base.crtc &&
|
|
|
|
|
to_intel_crtc(encoder->base.crtc)->active;
|
|
|
|
|
|
2016-08-23 16:18:07 +02:00
|
|
|
connector = intel_encoder_find_connector(encoder);
|
|
|
|
|
if (connector && !has_active_crtc) {
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
DRM_DEBUG_KMS("[ENCODER:%d:%s] has active connectors but no active pipe!\n",
|
|
|
|
|
encoder->base.base.id,
|
2014-06-03 14:56:21 +03:00
|
|
|
encoder->base.name);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
|
|
|
|
/* Connector is active, but has no active pipe. This is
|
|
|
|
|
* fallout from our resume register restoring. Disable
|
|
|
|
|
* the encoder manually again. */
|
|
|
|
|
if (encoder->base.crtc) {
|
2016-08-09 17:04:04 +02:00
|
|
|
struct drm_crtc_state *crtc_state = encoder->base.crtc->state;
|
|
|
|
|
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
|
|
|
|
|
encoder->base.base.id,
|
2014-06-03 14:56:21 +03:00
|
|
|
encoder->base.name);
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
|
2014-06-28 02:04:01 +03:00
|
|
|
if (encoder->post_disable)
|
2016-08-09 17:04:04 +02:00
|
|
|
encoder->post_disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
2014-04-25 10:56:22 +02:00
|
|
|
encoder->base.crtc = NULL;
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
|
|
|
|
/* Inconsistent output/port/pipe state happens presumably due to
|
|
|
|
|
* a bug in one of the get_hw_state functions. Or someplace else
|
|
|
|
|
* in our code, like the register restore mess on resume. Clamp
|
|
|
|
|
* things to off as a safer default. */
|
2016-08-09 17:04:04 +02:00
|
|
|
|
|
|
|
|
connector->base.dpms = DRM_MODE_DPMS_OFF;
|
|
|
|
|
connector->base.encoder = NULL;
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-16 08:55:39 +00:00
|
|
|
void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv)
|
2012-12-19 11:03:41 +01:00
|
|
|
{
|
2016-10-14 10:13:44 +01:00
|
|
|
i915_reg_t vga_reg = i915_vgacntrl_reg(dev_priv);
|
2012-12-19 11:03:41 +01:00
|
|
|
|
2014-02-18 00:02:16 +02:00
|
|
|
if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
|
|
|
|
|
DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
|
2016-11-16 08:55:39 +00:00
|
|
|
i915_disable_vga(dev_priv);
|
2014-02-18 00:02:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-16 08:55:39 +00:00
|
|
|
void i915_redisable_vga(struct drm_i915_private *dev_priv)
|
2014-02-18 00:02:16 +02:00
|
|
|
{
|
2013-08-02 16:22:24 -03:00
|
|
|
/* This function can be called both from intel_modeset_setup_hw_state or
|
|
|
|
|
* at a very early point in our resume sequence, where the power well
|
|
|
|
|
* structures are not yet restored. Since this function is at a very
|
|
|
|
|
* paranoid "someone might have enabled VGA while we were not looking"
|
|
|
|
|
* level, just check if the power well is enabled instead of trying to
|
|
|
|
|
* follow the "don't touch the power well if we don't need it" policy
|
|
|
|
|
* the rest of the driver uses. */
|
2016-02-12 18:55:13 +02:00
|
|
|
if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_VGA))
|
2013-08-02 16:22:24 -03:00
|
|
|
return;
|
|
|
|
|
|
2016-11-16 08:55:39 +00:00
|
|
|
i915_redisable_vga_power_on(dev_priv);
|
2016-02-12 18:55:13 +02:00
|
|
|
|
|
|
|
|
intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
|
2012-12-19 11:03:41 +01:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 18:59:08 +03:00
|
|
|
/* FIXME read out full plane state for all planes */
|
|
|
|
|
static void readout_plane_state(struct intel_crtc *crtc)
|
2015-06-15 12:33:51 +02:00
|
|
|
{
|
2017-11-17 21:19:09 +02:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
|
|
|
|
struct intel_crtc_state *crtc_state =
|
|
|
|
|
to_intel_crtc_state(crtc->base.state);
|
|
|
|
|
struct intel_plane *plane;
|
2015-06-15 12:33:51 +02:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
|
|
|
|
|
struct intel_plane_state *plane_state =
|
|
|
|
|
to_intel_plane_state(plane->base.state);
|
|
|
|
|
bool visible = plane->get_hw_state(plane);
|
2015-09-23 16:11:41 +02:00
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
intel_set_plane_visible(crtc_state, plane_state, visible);
|
|
|
|
|
}
|
2014-04-30 17:43:01 +03:00
|
|
|
}
|
|
|
|
|
|
2013-06-05 13:34:17 +02:00
|
|
|
static void intel_modeset_readout_hw_state(struct drm_device *dev)
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
enum pipe pipe;
|
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
struct intel_connector *connector;
|
2017-03-01 10:52:25 +01:00
|
|
|
struct drm_connector_list_iter conn_iter;
|
2013-06-05 13:34:16 +02:00
|
|
|
int i;
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
2015-12-10 12:33:57 +01:00
|
|
|
dev_priv->active_crtcs = 0;
|
|
|
|
|
|
2014-05-13 23:32:22 +01:00
|
|
|
for_each_intel_crtc(dev, crtc) {
|
2016-12-22 16:04:41 +02:00
|
|
|
struct intel_crtc_state *crtc_state =
|
|
|
|
|
to_intel_crtc_state(crtc->base.state);
|
2013-04-17 20:15:07 +02:00
|
|
|
|
2016-05-09 16:34:09 +02:00
|
|
|
__drm_atomic_helper_crtc_destroy_state(&crtc_state->base);
|
2015-12-10 12:33:57 +01:00
|
|
|
memset(crtc_state, 0, sizeof(*crtc_state));
|
|
|
|
|
crtc_state->base.crtc = &crtc->base;
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
2015-12-10 12:33:57 +01:00
|
|
|
crtc_state->base.active = crtc_state->base.enable =
|
|
|
|
|
dev_priv->display.get_pipe_config(crtc, crtc_state);
|
|
|
|
|
|
|
|
|
|
crtc->base.enabled = crtc_state->base.enable;
|
|
|
|
|
crtc->active = crtc_state->base.active;
|
|
|
|
|
|
2016-12-20 17:39:02 +02:00
|
|
|
if (crtc_state->base.active)
|
2015-12-10 12:33:57 +01:00
|
|
|
dev_priv->active_crtcs |= 1 << crtc->pipe;
|
|
|
|
|
|
2015-09-10 18:59:08 +03:00
|
|
|
readout_plane_state(crtc);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
2016-05-27 20:59:19 +03:00
|
|
|
DRM_DEBUG_KMS("[CRTC:%d:%s] hw state readout: %s\n",
|
|
|
|
|
crtc->base.base.id, crtc->base.name,
|
2016-12-22 16:04:41 +02:00
|
|
|
enableddisabled(crtc_state->base.active));
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-05 13:34:16 +02:00
|
|
|
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
|
|
|
|
|
struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
|
|
|
|
|
|
2016-03-08 17:46:21 +02:00
|
|
|
pll->on = pll->funcs.get_hw_state(dev_priv, pll,
|
2016-12-29 17:22:09 +02:00
|
|
|
&pll->state.hw_state);
|
|
|
|
|
pll->state.crtc_mask = 0;
|
2014-05-13 23:32:22 +01:00
|
|
|
for_each_intel_crtc(dev, crtc) {
|
2016-12-22 16:04:41 +02:00
|
|
|
struct intel_crtc_state *crtc_state =
|
|
|
|
|
to_intel_crtc_state(crtc->base.state);
|
|
|
|
|
|
|
|
|
|
if (crtc_state->base.active &&
|
|
|
|
|
crtc_state->shared_dpll == pll)
|
2016-12-29 17:22:09 +02:00
|
|
|
pll->state.crtc_mask |= 1 << crtc->pipe;
|
2013-06-05 13:34:16 +02:00
|
|
|
}
|
2016-12-29 17:22:09 +02:00
|
|
|
pll->active_mask = pll->state.crtc_mask;
|
2013-06-05 13:34:16 +02:00
|
|
|
|
2014-10-29 11:32:31 +02:00
|
|
|
DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n",
|
2016-12-29 17:22:09 +02:00
|
|
|
pll->name, pll->state.crtc_mask, pll->on);
|
2013-06-05 13:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
2014-08-05 11:29:37 +01:00
|
|
|
for_each_intel_encoder(dev, encoder) {
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
pipe = 0;
|
|
|
|
|
|
|
|
|
|
if (encoder->get_hw_state(encoder, &pipe)) {
|
2016-12-22 16:04:41 +02:00
|
|
|
struct intel_crtc_state *crtc_state;
|
|
|
|
|
|
2016-10-31 22:37:10 +02:00
|
|
|
crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
2016-12-22 16:04:41 +02:00
|
|
|
crtc_state = to_intel_crtc_state(crtc->base.state);
|
2016-10-31 22:37:05 +02:00
|
|
|
|
2013-05-14 17:08:26 -07:00
|
|
|
encoder->base.crtc = &crtc->base;
|
2016-12-22 16:04:41 +02:00
|
|
|
encoder->get_config(encoder, crtc_state);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
} else {
|
|
|
|
|
encoder->base.crtc = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-16 12:29:54 +01:00
|
|
|
DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n",
|
2016-11-17 12:30:14 +00:00
|
|
|
encoder->base.base.id, encoder->base.name,
|
|
|
|
|
enableddisabled(encoder->base.crtc),
|
2013-10-16 12:29:54 +01:00
|
|
|
pipe_name(pipe));
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-01 10:52:25 +01:00
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
|
|
|
for_each_intel_connector_iter(connector, &conn_iter) {
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
if (connector->get_hw_state(connector)) {
|
|
|
|
|
connector->base.dpms = DRM_MODE_DPMS_ON;
|
2016-01-06 14:53:25 +01:00
|
|
|
|
|
|
|
|
encoder = connector->encoder;
|
|
|
|
|
connector->base.encoder = &encoder->base;
|
|
|
|
|
|
|
|
|
|
if (encoder->base.crtc &&
|
|
|
|
|
encoder->base.crtc->state->active) {
|
|
|
|
|
/*
|
|
|
|
|
* This has to be done during hardware readout
|
|
|
|
|
* because anything calling .crtc_disable may
|
|
|
|
|
* rely on the connector_mask being accurate.
|
|
|
|
|
*/
|
|
|
|
|
encoder->base.crtc->state->connector_mask |=
|
|
|
|
|
1 << drm_connector_index(&connector->base);
|
2016-01-28 15:04:58 +01:00
|
|
|
encoder->base.crtc->state->encoder_mask |=
|
|
|
|
|
1 << drm_encoder_index(&encoder->base);
|
2016-01-06 14:53:25 +01:00
|
|
|
}
|
|
|
|
|
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
} else {
|
|
|
|
|
connector->base.dpms = DRM_MODE_DPMS_OFF;
|
|
|
|
|
connector->base.encoder = NULL;
|
|
|
|
|
}
|
|
|
|
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n",
|
2016-11-17 12:30:14 +00:00
|
|
|
connector->base.base.id, connector->base.name,
|
|
|
|
|
enableddisabled(connector->base.encoder));
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
2017-03-01 10:52:25 +01:00
|
|
|
drm_connector_list_iter_end(&conn_iter);
|
2015-09-10 18:59:07 +03:00
|
|
|
|
|
|
|
|
for_each_intel_crtc(dev, crtc) {
|
2016-12-22 16:04:41 +02:00
|
|
|
struct intel_crtc_state *crtc_state =
|
|
|
|
|
to_intel_crtc_state(crtc->base.state);
|
2017-08-30 21:57:03 +03:00
|
|
|
int min_cdclk = 0;
|
2016-12-20 17:39:02 +02:00
|
|
|
|
2015-09-10 18:59:07 +03:00
|
|
|
memset(&crtc->base.mode, 0, sizeof(crtc->base.mode));
|
2016-12-22 16:04:41 +02:00
|
|
|
if (crtc_state->base.active) {
|
|
|
|
|
intel_mode_from_pipe_config(&crtc->base.mode, crtc_state);
|
|
|
|
|
intel_mode_from_pipe_config(&crtc_state->base.adjusted_mode, crtc_state);
|
2015-09-10 18:59:07 +03:00
|
|
|
WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The initial mode needs to be set in order to keep
|
|
|
|
|
* the atomic core happy. It wants a valid mode if the
|
|
|
|
|
* crtc's enabled, so we do the above call.
|
|
|
|
|
*
|
2016-12-19 09:24:23 +01:00
|
|
|
* But we don't set all the derived state fully, hence
|
|
|
|
|
* set a flag to indicate that a full recalculation is
|
|
|
|
|
* needed on the next commit.
|
2015-09-10 18:59:07 +03:00
|
|
|
*/
|
2016-12-22 16:04:41 +02:00
|
|
|
crtc_state->base.mode.private_flags = I915_MODE_FLAG_INHERITED;
|
2015-09-10 18:59:10 +03:00
|
|
|
|
2017-01-26 21:50:31 +02:00
|
|
|
intel_crtc_compute_pixel_rate(crtc_state);
|
|
|
|
|
|
2017-07-10 22:33:47 +03:00
|
|
|
if (dev_priv->display.modeset_calc_cdclk) {
|
2017-08-30 21:57:03 +03:00
|
|
|
min_cdclk = intel_crtc_compute_min_cdclk(crtc_state);
|
2017-07-10 22:33:47 +03:00
|
|
|
if (WARN_ON(min_cdclk < 0))
|
|
|
|
|
min_cdclk = 0;
|
|
|
|
|
}
|
2016-12-20 17:39:02 +02:00
|
|
|
|
2017-05-09 16:03:29 +02:00
|
|
|
drm_calc_timestamping_constants(&crtc->base,
|
|
|
|
|
&crtc_state->base.adjusted_mode);
|
2015-09-10 18:59:10 +03:00
|
|
|
update_scanline_offset(crtc);
|
2015-09-10 18:59:07 +03:00
|
|
|
}
|
2016-02-17 21:41:09 +02:00
|
|
|
|
2017-08-30 21:57:03 +03:00
|
|
|
dev_priv->min_cdclk[crtc->pipe] = min_cdclk;
|
2017-10-24 12:52:14 +03:00
|
|
|
dev_priv->min_voltage_level[crtc->pipe] =
|
|
|
|
|
crtc_state->min_voltage_level;
|
2016-12-20 17:39:02 +02:00
|
|
|
|
2016-12-22 16:04:41 +02:00
|
|
|
intel_pipe_config_sanity_check(dev_priv, crtc_state);
|
2015-09-10 18:59:07 +03:00
|
|
|
}
|
2013-06-05 13:34:17 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-24 16:19:59 +02:00
|
|
|
static void
|
|
|
|
|
get_encoder_power_domains(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
struct intel_encoder *encoder;
|
|
|
|
|
|
|
|
|
|
for_each_intel_encoder(&dev_priv->drm, encoder) {
|
|
|
|
|
u64 get_domains;
|
|
|
|
|
enum intel_display_power_domain domain;
|
|
|
|
|
|
|
|
|
|
if (!encoder->get_power_domains)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
get_domains = encoder->get_power_domains(encoder);
|
|
|
|
|
for_each_power_domain(domain, get_domains)
|
|
|
|
|
intel_display_power_get(dev_priv, domain);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-10 16:03:19 -08:00
|
|
|
static void intel_early_display_was(struct drm_i915_private *dev_priv)
|
|
|
|
|
{
|
|
|
|
|
/* Display WA #1185 WaDisableDARBFClkGating:cnl,glk */
|
|
|
|
|
if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
|
|
|
|
|
I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
|
|
|
|
|
DARBF_GATING_DIS);
|
|
|
|
|
|
|
|
|
|
if (IS_HASWELL(dev_priv)) {
|
|
|
|
|
/*
|
|
|
|
|
* WaRsPkgCStateDisplayPMReq:hsw
|
|
|
|
|
* System hang if this isn't done before disabling all planes!
|
|
|
|
|
*/
|
|
|
|
|
I915_WRITE(CHICKEN_PAR1_1,
|
|
|
|
|
I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-13 16:30:25 +02:00
|
|
|
/* Scan out the current hw modeset state,
|
|
|
|
|
* and sanitizes it to the current state
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-06-01 17:36:13 +03:00
|
|
|
intel_modeset_setup_hw_state(struct drm_device *dev,
|
|
|
|
|
struct drm_modeset_acquire_ctx *ctx)
|
2013-06-05 13:34:17 +02:00
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2013-06-05 13:34:17 +02:00
|
|
|
enum pipe pipe;
|
|
|
|
|
struct intel_crtc *crtc;
|
|
|
|
|
struct intel_encoder *encoder;
|
2013-07-17 06:55:04 +02:00
|
|
|
int i;
|
2013-06-05 13:34:17 +02:00
|
|
|
|
2017-11-10 16:03:19 -08:00
|
|
|
intel_early_display_was(dev_priv);
|
2013-06-05 13:34:17 +02:00
|
|
|
intel_modeset_readout_hw_state(dev);
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
|
|
|
|
|
/* HW state is read out, now we need to sanitize this mess. */
|
2017-02-24 16:19:59 +02:00
|
|
|
get_encoder_power_domains(dev_priv);
|
|
|
|
|
|
2017-11-17 21:19:09 +02:00
|
|
|
intel_sanitize_plane_mapping(dev_priv);
|
|
|
|
|
|
2014-08-05 11:29:37 +01:00
|
|
|
for_each_intel_encoder(dev, encoder) {
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
intel_sanitize_encoder(encoder);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-18 13:49:10 +01:00
|
|
|
for_each_pipe(dev_priv, pipe) {
|
2016-10-31 22:37:10 +02:00
|
|
|
crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
2016-10-31 22:37:05 +02:00
|
|
|
|
2017-06-01 17:36:13 +03:00
|
|
|
intel_sanitize_crtc(crtc, ctx);
|
2015-01-15 14:55:25 +02:00
|
|
|
intel_dump_pipe_config(crtc, crtc->config,
|
|
|
|
|
"[setup_hw_state]");
|
drm/i915: read out the modeset hw state at load and resume time
... instead of resetting a few things and hoping that this will work
out.
To properly disable the output pipelines at the initial modeset after
resume or boot up we need to have an accurate picture of which outputs
are enabled and connected to which crtcs. Otherwise we risk disabling
things at the wrong time, which can lead to hangs (or at least royally
confused panels), both requiring a walk to the reset button to fix.
Hence read out the hw state with the freshly introduce get_hw_state
functions and then sanitize it afterwards.
For a full modeset readout (which would allow us to avoid the initial
modeset at boot up) a few things are still missing:
- Reading out the mode from the pipe, especially the dotclock
computation is quite some fun.
- Reading out the parameters for the stolen memory framebuffer and
wrapping it up.
- Reading out the pch pll connections - luckily the disable code
simply bails out if the crtc doesn't have a pch pll attached (even
for configurations that would need one).
This patch here turned up tons of smelly stuff around resume: We
restore tons of register in seemingly random way (well, not quite, but
we're not too careful either), which leaves the hw in a rather
ill-defined state: E.g. the port registers are sometimes
unconditionally restore (lvds, crt), leaving us with an active
encoder/connector but no active pipe connected to it. Luckily the hw
state sanitizer detects this madness and fixes things up a bit.
v2: When checking whether an encoder with active connectors has a crtc
wire up to it, check for both the crtc _and_ it's active state.
v3:
- Extract intel_sanitize_encoder.
- Manually disable active encoders without an active pipe.
v4: Correclty fix up the pipe<->plane mapping on machines where we
switch pipes/planes. Noticed by Chris Wilson, who also provided the
fixup.
v5: Spelling fix in a comment, noticed by Paulo Zanoni
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-02 20:28:59 +02:00
|
|
|
}
|
drm/i915: stage modeset output changes
This is the core of the new modeset logic.
The current code which is based upon the crtc helper code first
updates all the link of the new display pipeline and then calls the
lower-level set_mode function to execute the required callbacks to get
there. The issue with this approach is that for disabling we need to
know the _current_ display pipe state, not the new one.
Hence we need to stage the new state of the display pipe and only
update it once we have disabled the current configuration and before we
start to update the hw registers with the new configuration.
This patch here just prepares the ground by switching the new output
state computation to these staging pointers. To make it clearer,
rename the old update_output_state function to stage_output_state.
A few peculiarities:
- We're also calling the set_mode function at various places to update
properties. Hence after a successfule modeset we need to stage the
current configuration (for otherwise we might fall back again). This
happens automatically because as part of the (successful) modeset we
need to copy the staged state to the real one. But for the hw
readout code we need to make sure that this happens, too.
- Teach the new staged output state computation code the required
smarts to handle the disabling of outputs. The current code handles
this in a special case, but to better handle global modeset changes
covering more than one crtc, we want to do this all in the same
low-level modeset code.
- The actual modeset code is still a bit ugly and wants to know the new
crtc->enabled state a bit early. Follow-on patches will clean that
up, for now we have to apply the staged output configuration early,
outside of the set_mode functions.
- Improve/add comments in stage_output_state.
Essentially all that is left to do now is move the disabling code into
set_mode and then move the staged state update code also into
set_mode, at the right place between disabling things and calling the
mode_set callbacks for the new configuration.
v2: Disabling a crtc works by passing in a NULL mode or fb, userspace
doesn't hand in the list of connectors. We therefore need to detect
this case manually and tear down all the output links.
v3: Properly update the output staging pointers after having read out
the hw state.
v4: Simplify the code, add more DRM_DEBUG_KMS output and check a few
assumptions with WARN_ON. Essentially all things that I've noticed
while debugging issues in other places of the code.
v4: Correctly disable the old set of connectors when enabling an
already enabled crtc on a new set of crtc. Reported by Paulo Zanoni.
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2012-07-05 22:34:27 +02:00
|
|
|
|
2015-03-20 16:18:05 +02:00
|
|
|
intel_modeset_update_connector_atomic_state(dev);
|
|
|
|
|
|
2013-07-17 06:55:04 +02:00
|
|
|
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
|
|
|
|
|
struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
|
|
|
|
|
|
2016-03-14 09:27:52 +01:00
|
|
|
if (!pll->on || pll->active_mask)
|
2013-07-17 06:55:04 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name);
|
|
|
|
|
|
2016-03-08 17:46:21 +02:00
|
|
|
pll->funcs.disable(dev_priv, pll);
|
2013-07-17 06:55:04 +02:00
|
|
|
pll->on = false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-21 21:14:29 +03:00
|
|
|
if (IS_G4X(dev_priv)) {
|
|
|
|
|
g4x_wm_get_hw_state(dev);
|
|
|
|
|
g4x_wm_sanitize(dev_priv);
|
|
|
|
|
} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
|
2015-06-24 22:00:03 +03:00
|
|
|
vlv_wm_get_hw_state(dev);
|
2017-03-02 19:15:02 +02:00
|
|
|
vlv_wm_sanitize(dev_priv);
|
2017-08-09 13:52:48 -07:00
|
|
|
} else if (INTEL_GEN(dev_priv) >= 9) {
|
2014-11-04 17:06:45 +00:00
|
|
|
skl_wm_get_hw_state(dev);
|
2017-03-02 19:15:02 +02:00
|
|
|
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
2013-10-14 14:55:24 +03:00
|
|
|
ilk_wm_get_hw_state(dev);
|
2017-03-02 19:15:02 +02:00
|
|
|
}
|
2015-07-13 16:30:27 +02:00
|
|
|
|
|
|
|
|
for_each_intel_crtc(dev, crtc) {
|
2017-02-09 11:31:21 +02:00
|
|
|
u64 put_domains;
|
2015-07-13 16:30:27 +02:00
|
|
|
|
2016-02-10 13:49:36 +01:00
|
|
|
put_domains = modeset_get_crtc_power_domains(&crtc->base, crtc->config);
|
2015-07-13 16:30:27 +02:00
|
|
|
if (WARN_ON(put_domains))
|
|
|
|
|
modeset_put_power_domains(dev_priv, put_domains);
|
|
|
|
|
}
|
|
|
|
|
intel_display_set_init_power(dev_priv, false);
|
2016-01-19 11:35:48 -02:00
|
|
|
|
2017-02-17 17:39:46 +02:00
|
|
|
intel_power_domains_verify_state(dev_priv);
|
|
|
|
|
|
2016-01-19 11:35:48 -02:00
|
|
|
intel_fbc_init_pipe_state(dev_priv);
|
2015-07-13 16:30:25 +02:00
|
|
|
}
|
2013-09-16 17:38:33 +03:00
|
|
|
|
2015-07-13 16:30:25 +02:00
|
|
|
void intel_display_resume(struct drm_device *dev)
|
|
|
|
|
{
|
2016-02-16 10:06:14 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
|
|
|
struct drm_atomic_state *state = dev_priv->modeset_restore_state;
|
|
|
|
|
struct drm_modeset_acquire_ctx ctx;
|
2015-07-13 16:30:25 +02:00
|
|
|
int ret;
|
2013-04-11 20:22:50 +02:00
|
|
|
|
2016-02-16 10:06:14 +01:00
|
|
|
dev_priv->modeset_restore_state = NULL;
|
2016-08-05 23:28:27 +03:00
|
|
|
if (state)
|
|
|
|
|
state->acquire_ctx = &ctx;
|
2015-07-13 16:30:25 +02:00
|
|
|
|
2016-02-16 10:06:14 +01:00
|
|
|
drm_modeset_acquire_init(&ctx, 0);
|
2015-07-13 16:30:25 +02:00
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
while (1) {
|
|
|
|
|
ret = drm_modeset_lock_all_ctx(dev, &ctx);
|
|
|
|
|
if (ret != -EDEADLK)
|
|
|
|
|
break;
|
2015-07-13 16:30:25 +02:00
|
|
|
|
2016-02-16 10:06:14 +01:00
|
|
|
drm_modeset_backoff(&ctx);
|
|
|
|
|
}
|
2015-07-13 16:30:25 +02:00
|
|
|
|
2016-08-05 23:28:27 +03:00
|
|
|
if (!ret)
|
2017-01-16 10:37:38 +01:00
|
|
|
ret = __intel_display_resume(dev, state, &ctx);
|
2016-08-05 23:28:27 +03:00
|
|
|
|
2017-08-17 19:15:28 +05:30
|
|
|
intel_enable_ipc(dev_priv);
|
2016-02-16 10:06:14 +01:00
|
|
|
drm_modeset_drop_locks(&ctx);
|
|
|
|
|
drm_modeset_acquire_fini(&ctx);
|
2015-07-13 16:30:25 +02:00
|
|
|
|
2016-10-14 13:18:18 +01:00
|
|
|
if (ret)
|
2016-02-16 10:06:14 +01:00
|
|
|
DRM_ERROR("Restoring old state failed with %i\n", ret);
|
2017-01-15 12:58:25 +00:00
|
|
|
if (state)
|
|
|
|
|
drm_atomic_state_put(state);
|
2011-03-29 10:40:27 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-24 14:00:15 +01:00
|
|
|
int intel_connector_register(struct drm_connector *connector)
|
|
|
|
|
{
|
|
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = intel_backlight_device_register(intel_connector);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
return 0;
|
2014-11-07 15:19:46 +02:00
|
|
|
|
2016-06-24 14:00:15 +01:00
|
|
|
err:
|
|
|
|
|
return ret;
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2016-06-17 11:40:33 +01:00
|
|
|
void intel_connector_unregister(struct drm_connector *connector)
|
2014-02-11 17:12:48 +02:00
|
|
|
{
|
2016-06-17 11:40:34 +01:00
|
|
|
struct intel_connector *intel_connector = to_intel_connector(connector);
|
2014-02-11 17:12:48 +02:00
|
|
|
|
2016-06-17 11:40:34 +01:00
|
|
|
intel_backlight_device_unregister(intel_connector);
|
2014-02-11 17:12:48 +02:00
|
|
|
intel_panel_destroy_backlight(connector);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-26 14:52:00 -07:00
|
|
|
static void intel_hpd_poll_fini(struct drm_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct intel_connector *connector;
|
|
|
|
|
struct drm_connector_list_iter conn_iter;
|
|
|
|
|
|
2017-11-28 11:01:47 +00:00
|
|
|
/* Kill all the work that may have been queued by hpd. */
|
2017-10-26 14:52:00 -07:00
|
|
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
|
|
|
for_each_intel_connector_iter(connector, &conn_iter) {
|
|
|
|
|
if (connector->modeset_retry_work.func)
|
|
|
|
|
cancel_work_sync(&connector->modeset_retry_work);
|
|
|
|
|
}
|
|
|
|
|
drm_connector_list_iter_end(&conn_iter);
|
|
|
|
|
}
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
void intel_modeset_cleanup(struct drm_device *dev)
|
|
|
|
|
{
|
2016-07-04 11:34:36 +01:00
|
|
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
2009-08-17 13:31:43 -07:00
|
|
|
|
2017-01-23 21:29:39 +00:00
|
|
|
flush_work(&dev_priv->atomic_helper.free_work);
|
|
|
|
|
WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list));
|
|
|
|
|
|
2016-05-10 14:10:04 +01:00
|
|
|
intel_disable_gt_powersave(dev_priv);
|
2014-11-19 15:30:05 +02:00
|
|
|
|
2013-04-24 11:13:35 +02:00
|
|
|
/*
|
|
|
|
|
* Interrupts and polling as the first thing to avoid creating havoc.
|
2014-11-19 15:30:05 +02:00
|
|
|
* Too much stuff here (turning of connectors, ...) would
|
2013-04-24 11:13:35 +02:00
|
|
|
* experience fancy races otherwise.
|
|
|
|
|
*/
|
2014-09-30 10:56:43 +02:00
|
|
|
intel_irq_uninstall(dev_priv);
|
2014-06-20 11:57:33 -07:00
|
|
|
|
2013-04-24 11:13:35 +02:00
|
|
|
/*
|
|
|
|
|
* Due to the hpd irq storm handling the hotplug work can re-arm the
|
|
|
|
|
* poll handlers. Hence disable polling after hpd handling is shut down.
|
|
|
|
|
*/
|
2017-10-26 14:52:00 -07:00
|
|
|
intel_hpd_poll_fini(dev);
|
2013-04-24 11:13:35 +02:00
|
|
|
|
2017-07-15 00:46:55 +02:00
|
|
|
/* poll work can call into fbdev, hence clean that up afterwards */
|
|
|
|
|
intel_fbdev_fini(dev_priv);
|
|
|
|
|
|
2010-10-07 16:01:13 -07:00
|
|
|
intel_unregister_dsm_handler();
|
|
|
|
|
|
2016-01-19 11:35:46 -02:00
|
|
|
intel_fbc_global_disable(dev_priv);
|
2009-11-11 12:19:17 -05:00
|
|
|
|
2011-07-08 12:22:42 +01:00
|
|
|
/* flush any delayed tasks or pending work */
|
|
|
|
|
flush_scheduled_work();
|
|
|
|
|
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
drm_mode_config_cleanup(dev);
|
2012-12-18 15:24:37 +01:00
|
|
|
|
2016-05-12 12:43:23 +01:00
|
|
|
intel_cleanup_overlay(dev_priv);
|
2014-03-31 15:10:44 +03:00
|
|
|
|
2016-05-10 14:10:04 +01:00
|
|
|
intel_cleanup_gt_powersave(dev_priv);
|
2016-01-13 11:55:28 +01:00
|
|
|
|
2016-12-01 14:16:42 +00:00
|
|
|
intel_teardown_gmbus(dev_priv);
|
2017-11-13 15:36:22 +02:00
|
|
|
|
|
|
|
|
destroy_workqueue(dev_priv->modeset_wq);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
|
|
|
|
|
2010-09-09 16:20:55 +01:00
|
|
|
void intel_connector_attach_encoder(struct intel_connector *connector,
|
|
|
|
|
struct intel_encoder *encoder)
|
|
|
|
|
{
|
|
|
|
|
connector->encoder = encoder;
|
|
|
|
|
drm_mode_connector_attach_encoder(&connector->base,
|
|
|
|
|
&encoder->base);
|
DRM: i915: add mode setting support
This commit adds i915 driver support for the DRM mode setting APIs.
Currently, VGA, LVDS, SDVO DVI & VGA, TV and DVO LVDS outputs are
supported. HDMI, DisplayPort and additional SDVO output support will
follow.
Support for the mode setting code is controlled by the new 'modeset'
module option. A new config option, CONFIG_DRM_I915_KMS controls the
default behavior, and whether a PCI ID list is built into the module for
use by user level module utilities.
Note that if mode setting is enabled, user level drivers that access
display registers directly or that don't use the kernel graphics memory
manager will likely corrupt kernel graphics memory, disrupt output
configuration (possibly leading to hangs and/or blank displays), and
prevent panic/oops messages from appearing. So use caution when
enabling this code; be sure your user level code supports the new
interfaces.
A new SysRq key, 'g', provides emergency support for switching back to
the kernel's framebuffer console; which is useful for testing.
Co-authors: Dave Airlie <airlied@linux.ie>, Hong Liu <hong.liu@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2008-11-07 14:24:08 -08:00
|
|
|
}
|
2009-09-21 14:33:58 +10:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* set vga decode state - true == enable VGA decode
|
|
|
|
|
*/
|
2016-11-16 12:32:42 +00:00
|
|
|
int intel_modeset_vga_set_state(struct drm_i915_private *dev_priv, bool state)
|
2009-09-21 14:33:58 +10:00
|
|
|
{
|
2016-11-16 12:32:42 +00:00
|
|
|
unsigned reg = INTEL_GEN(dev_priv) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
|
2009-09-21 14:33:58 +10:00
|
|
|
u16 gmch_ctrl;
|
|
|
|
|
|
2014-02-07 18:37:02 -02:00
|
|
|
if (pci_read_config_word(dev_priv->bridge_dev, reg, &gmch_ctrl)) {
|
|
|
|
|
DRM_ERROR("failed to read control word\n");
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-07 18:37:03 -02:00
|
|
|
if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !state)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2009-09-21 14:33:58 +10:00
|
|
|
if (state)
|
|
|
|
|
gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
|
|
|
|
|
else
|
|
|
|
|
gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
|
2014-02-07 18:37:02 -02:00
|
|
|
|
|
|
|
|
if (pci_write_config_word(dev_priv->bridge_dev, reg, gmch_ctrl)) {
|
|
|
|
|
DRM_ERROR("failed to write control word\n");
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-21 14:33:58 +10:00
|
|
|
return 0;
|
|
|
|
|
}
|
2010-11-21 13:12:35 +00:00
|
|
|
|
2016-10-12 10:05:18 +01:00
|
|
|
#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
|
|
|
|
|
|
2010-11-21 13:12:35 +00:00
|
|
|
struct intel_display_error_state {
|
2013-05-03 12:15:37 -03:00
|
|
|
|
|
|
|
|
u32 power_well_driver;
|
|
|
|
|
|
2013-08-08 15:12:06 +02:00
|
|
|
int num_transcoders;
|
|
|
|
|
|
2010-11-21 13:12:35 +00:00
|
|
|
struct intel_cursor_error_state {
|
|
|
|
|
u32 control;
|
|
|
|
|
u32 position;
|
|
|
|
|
u32 base;
|
|
|
|
|
u32 size;
|
2012-08-15 19:23:25 +01:00
|
|
|
} cursor[I915_MAX_PIPES];
|
2010-11-21 13:12:35 +00:00
|
|
|
|
|
|
|
|
struct intel_pipe_error_state {
|
2013-11-27 22:02:02 +02:00
|
|
|
bool power_domain_on;
|
2010-11-21 13:12:35 +00:00
|
|
|
u32 source;
|
2014-04-18 15:55:04 +03:00
|
|
|
u32 stat;
|
2012-08-15 19:23:25 +01:00
|
|
|
} pipe[I915_MAX_PIPES];
|
2010-11-21 13:12:35 +00:00
|
|
|
|
|
|
|
|
struct intel_plane_error_state {
|
|
|
|
|
u32 control;
|
|
|
|
|
u32 stride;
|
|
|
|
|
u32 size;
|
|
|
|
|
u32 pos;
|
|
|
|
|
u32 addr;
|
|
|
|
|
u32 surface;
|
|
|
|
|
u32 tile_offset;
|
2012-08-15 19:23:25 +01:00
|
|
|
} plane[I915_MAX_PIPES];
|
2013-08-08 15:12:06 +02:00
|
|
|
|
|
|
|
|
struct intel_transcoder_error_state {
|
2013-11-27 22:02:02 +02:00
|
|
|
bool power_domain_on;
|
2013-08-08 15:12:06 +02:00
|
|
|
enum transcoder cpu_transcoder;
|
|
|
|
|
|
|
|
|
|
u32 conf;
|
|
|
|
|
|
|
|
|
|
u32 htotal;
|
|
|
|
|
u32 hblank;
|
|
|
|
|
u32 hsync;
|
|
|
|
|
u32 vtotal;
|
|
|
|
|
u32 vblank;
|
|
|
|
|
u32 vsync;
|
|
|
|
|
} transcoder[4];
|
2010-11-21 13:12:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct intel_display_error_state *
|
2016-05-06 15:40:21 +01:00
|
|
|
intel_display_capture_error_state(struct drm_i915_private *dev_priv)
|
2010-11-21 13:12:35 +00:00
|
|
|
{
|
|
|
|
|
struct intel_display_error_state *error;
|
2013-08-08 15:12:06 +02:00
|
|
|
int transcoders[] = {
|
|
|
|
|
TRANSCODER_A,
|
|
|
|
|
TRANSCODER_B,
|
|
|
|
|
TRANSCODER_C,
|
|
|
|
|
TRANSCODER_EDP,
|
|
|
|
|
};
|
2010-11-21 13:12:35 +00:00
|
|
|
int i;
|
|
|
|
|
|
2016-05-06 15:40:21 +01:00
|
|
|
if (INTEL_INFO(dev_priv)->num_pipes == 0)
|
2013-08-08 15:12:06 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
2013-11-01 13:32:08 -02:00
|
|
|
error = kzalloc(sizeof(*error), GFP_ATOMIC);
|
2010-11-21 13:12:35 +00:00
|
|
|
if (error == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2016-05-06 15:40:21 +01:00
|
|
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
|
2017-08-14 18:15:30 +03:00
|
|
|
error->power_well_driver =
|
|
|
|
|
I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL));
|
2013-05-03 12:15:37 -03:00
|
|
|
|
2014-08-18 13:49:10 +01:00
|
|
|
for_each_pipe(dev_priv, i) {
|
2013-11-27 22:02:02 +02:00
|
|
|
error->pipe[i].power_domain_on =
|
2014-09-30 10:56:39 +02:00
|
|
|
__intel_display_power_is_enabled(dev_priv,
|
|
|
|
|
POWER_DOMAIN_PIPE(i));
|
2013-11-27 22:02:02 +02:00
|
|
|
if (!error->pipe[i].power_domain_on)
|
2013-11-01 13:32:08 -02:00
|
|
|
continue;
|
|
|
|
|
|
2014-04-09 13:28:53 +03:00
|
|
|
error->cursor[i].control = I915_READ(CURCNTR(i));
|
|
|
|
|
error->cursor[i].position = I915_READ(CURPOS(i));
|
|
|
|
|
error->cursor[i].base = I915_READ(CURBASE(i));
|
2010-11-21 13:12:35 +00:00
|
|
|
|
|
|
|
|
error->plane[i].control = I915_READ(DSPCNTR(i));
|
|
|
|
|
error->plane[i].stride = I915_READ(DSPSTRIDE(i));
|
2016-05-06 15:40:21 +01:00
|
|
|
if (INTEL_GEN(dev_priv) <= 3) {
|
2013-03-06 20:03:13 -03:00
|
|
|
error->plane[i].size = I915_READ(DSPSIZE(i));
|
2013-03-22 14:20:57 -03:00
|
|
|
error->plane[i].pos = I915_READ(DSPPOS(i));
|
|
|
|
|
}
|
2016-05-06 15:40:21 +01:00
|
|
|
if (INTEL_GEN(dev_priv) <= 7 && !IS_HASWELL(dev_priv))
|
2013-03-06 20:03:14 -03:00
|
|
|
error->plane[i].addr = I915_READ(DSPADDR(i));
|
2016-05-06 15:40:21 +01:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2010-11-21 13:12:35 +00:00
|
|
|
error->plane[i].surface = I915_READ(DSPSURF(i));
|
|
|
|
|
error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error->pipe[i].source = I915_READ(PIPESRC(i));
|
2014-04-18 15:55:04 +03:00
|
|
|
|
2016-05-06 15:40:21 +01:00
|
|
|
if (HAS_GMCH_DISPLAY(dev_priv))
|
2014-04-18 15:55:04 +03:00
|
|
|
error->pipe[i].stat = I915_READ(PIPESTAT(i));
|
2013-08-08 15:12:06 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-18 17:05:42 +02:00
|
|
|
/* Note: this does not include DSI transcoders. */
|
2016-05-06 15:40:21 +01:00
|
|
|
error->num_transcoders = INTEL_INFO(dev_priv)->num_pipes;
|
2016-04-07 11:08:05 +03:00
|
|
|
if (HAS_DDI(dev_priv))
|
2013-08-08 15:12:06 +02:00
|
|
|
error->num_transcoders++; /* Account for eDP. */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < error->num_transcoders; i++) {
|
|
|
|
|
enum transcoder cpu_transcoder = transcoders[i];
|
|
|
|
|
|
2013-11-27 22:02:02 +02:00
|
|
|
error->transcoder[i].power_domain_on =
|
2014-09-30 10:56:39 +02:00
|
|
|
__intel_display_power_is_enabled(dev_priv,
|
2013-12-20 15:09:41 -02:00
|
|
|
POWER_DOMAIN_TRANSCODER(cpu_transcoder));
|
2013-11-27 22:02:02 +02:00
|
|
|
if (!error->transcoder[i].power_domain_on)
|
2013-11-01 13:32:08 -02:00
|
|
|
continue;
|
|
|
|
|
|
2013-08-08 15:12:06 +02:00
|
|
|
error->transcoder[i].cpu_transcoder = cpu_transcoder;
|
|
|
|
|
|
|
|
|
|
error->transcoder[i].conf = I915_READ(PIPECONF(cpu_transcoder));
|
|
|
|
|
error->transcoder[i].htotal = I915_READ(HTOTAL(cpu_transcoder));
|
|
|
|
|
error->transcoder[i].hblank = I915_READ(HBLANK(cpu_transcoder));
|
|
|
|
|
error->transcoder[i].hsync = I915_READ(HSYNC(cpu_transcoder));
|
|
|
|
|
error->transcoder[i].vtotal = I915_READ(VTOTAL(cpu_transcoder));
|
|
|
|
|
error->transcoder[i].vblank = I915_READ(VBLANK(cpu_transcoder));
|
|
|
|
|
error->transcoder[i].vsync = I915_READ(VSYNC(cpu_transcoder));
|
2010-11-21 13:12:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-23 13:55:35 +03:00
|
|
|
#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
|
|
|
|
|
|
2010-11-21 13:12:35 +00:00
|
|
|
void
|
2013-05-23 13:55:35 +03:00
|
|
|
intel_display_print_error_state(struct drm_i915_error_state_buf *m,
|
2010-11-21 13:12:35 +00:00
|
|
|
struct intel_display_error_state *error)
|
|
|
|
|
{
|
2017-02-14 16:46:11 +00:00
|
|
|
struct drm_i915_private *dev_priv = m->i915;
|
2010-11-21 13:12:35 +00:00
|
|
|
int i;
|
|
|
|
|
|
2013-08-08 15:12:06 +02:00
|
|
|
if (!error)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-11-09 11:30:45 +00:00
|
|
|
err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev_priv)->num_pipes);
|
2016-10-13 11:03:00 +01:00
|
|
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, "PWR_WELL_CTL2: %08x\n",
|
2013-05-03 12:15:37 -03:00
|
|
|
error->power_well_driver);
|
2014-08-18 13:49:10 +01:00
|
|
|
for_each_pipe(dev_priv, i) {
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, "Pipe [%d]:\n", i);
|
2013-11-27 22:02:02 +02:00
|
|
|
err_printf(m, " Power: %s\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(error->pipe[i].power_domain_on));
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, " SRC: %08x\n", error->pipe[i].source);
|
2014-04-18 15:55:04 +03:00
|
|
|
err_printf(m, " STAT: %08x\n", error->pipe[i].stat);
|
2013-05-23 13:55:35 +03:00
|
|
|
|
|
|
|
|
err_printf(m, "Plane [%d]:\n", i);
|
|
|
|
|
err_printf(m, " CNTR: %08x\n", error->plane[i].control);
|
|
|
|
|
err_printf(m, " STRIDE: %08x\n", error->plane[i].stride);
|
2016-11-16 08:55:37 +00:00
|
|
|
if (INTEL_GEN(dev_priv) <= 3) {
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, " SIZE: %08x\n", error->plane[i].size);
|
|
|
|
|
err_printf(m, " POS: %08x\n", error->plane[i].pos);
|
2013-03-22 14:20:57 -03:00
|
|
|
}
|
2016-10-13 11:03:01 +01:00
|
|
|
if (INTEL_GEN(dev_priv) <= 7 && !IS_HASWELL(dev_priv))
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, " ADDR: %08x\n", error->plane[i].addr);
|
2016-11-16 08:55:37 +00:00
|
|
|
if (INTEL_GEN(dev_priv) >= 4) {
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, " SURF: %08x\n", error->plane[i].surface);
|
|
|
|
|
err_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset);
|
2010-11-21 13:12:35 +00:00
|
|
|
}
|
|
|
|
|
|
2013-05-23 13:55:35 +03:00
|
|
|
err_printf(m, "Cursor [%d]:\n", i);
|
|
|
|
|
err_printf(m, " CNTR: %08x\n", error->cursor[i].control);
|
|
|
|
|
err_printf(m, " POS: %08x\n", error->cursor[i].position);
|
|
|
|
|
err_printf(m, " BASE: %08x\n", error->cursor[i].base);
|
2010-11-21 13:12:35 +00:00
|
|
|
}
|
2013-08-08 15:12:06 +02:00
|
|
|
|
|
|
|
|
for (i = 0; i < error->num_transcoders; i++) {
|
2016-03-15 21:51:10 +02:00
|
|
|
err_printf(m, "CPU transcoder: %s\n",
|
2013-08-08 15:12:06 +02:00
|
|
|
transcoder_name(error->transcoder[i].cpu_transcoder));
|
2013-11-27 22:02:02 +02:00
|
|
|
err_printf(m, " Power: %s\n",
|
2016-01-14 12:53:34 +02:00
|
|
|
onoff(error->transcoder[i].power_domain_on));
|
2013-08-08 15:12:06 +02:00
|
|
|
err_printf(m, " CONF: %08x\n", error->transcoder[i].conf);
|
|
|
|
|
err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal);
|
|
|
|
|
err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank);
|
|
|
|
|
err_printf(m, " HSYNC: %08x\n", error->transcoder[i].hsync);
|
|
|
|
|
err_printf(m, " VTOTAL: %08x\n", error->transcoder[i].vtotal);
|
|
|
|
|
err_printf(m, " VBLANK: %08x\n", error->transcoder[i].vblank);
|
|
|
|
|
err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync);
|
|
|
|
|
}
|
2010-11-21 13:12:35 +00:00
|
|
|
}
|
2016-10-12 10:05:18 +01:00
|
|
|
|
|
|
|
|
#endif
|