Merge tag 'v4.4-rc2' into drm-intel-next-queued
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 23 Nov 2015 08:04:05 +0000 (09:04 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 23 Nov 2015 08:04:05 +0000 (09:04 +0100)
Linux 4.4-rc2

Backmerge to get at

commit 1b0e3a049efe471c399674fd954500ce97438d30
Author: Imre Deak <imre.deak@intel.com>
Date:   Thu Nov 5 23:04:11 2015 +0200

    drm/i915/skl: disable display side power well support for now

so that we can proplery re-eanble skl power wells in -next.

Conflicts are just adjacent lines changed, except for intel_fbdev.c
where we need to interleave the changs. Nothing nefarious.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
22 files changed:
1  2 
Documentation/DocBook/gpu.tmpl
arch/x86/kernel/early-quirks.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_fence.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_guc_loader.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lrc.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/pci/quirks.c

index 0000000,201dcd3..3bf810e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,4286 +1,4290 @@@
 -      <title>GuC-based Command Submission</title>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+ <book id="gpuDevelopersGuide">
+   <bookinfo>
+     <title>Linux GPU Driver Developer's Guide</title>
+     <authorgroup>
+       <author>
+       <firstname>Jesse</firstname>
+       <surname>Barnes</surname>
+       <contrib>Initial version</contrib>
+       <affiliation>
+         <orgname>Intel Corporation</orgname>
+         <address>
+           <email>jesse.barnes@intel.com</email>
+         </address>
+       </affiliation>
+       </author>
+       <author>
+       <firstname>Laurent</firstname>
+       <surname>Pinchart</surname>
+       <contrib>Driver internals</contrib>
+       <affiliation>
+         <orgname>Ideas on board SPRL</orgname>
+         <address>
+           <email>laurent.pinchart@ideasonboard.com</email>
+         </address>
+       </affiliation>
+       </author>
+       <author>
+       <firstname>Daniel</firstname>
+       <surname>Vetter</surname>
+       <contrib>Contributions all over the place</contrib>
+       <affiliation>
+         <orgname>Intel Corporation</orgname>
+         <address>
+           <email>daniel.vetter@ffwll.ch</email>
+         </address>
+       </affiliation>
+       </author>
+       <author>
+       <firstname>Lukas</firstname>
+       <surname>Wunner</surname>
+       <contrib>vga_switcheroo documentation</contrib>
+       <affiliation>
+         <address>
+           <email>lukas@wunner.de</email>
+         </address>
+       </affiliation>
+       </author>
+     </authorgroup>
+     <copyright>
+       <year>2008-2009</year>
+       <year>2013-2014</year>
+       <holder>Intel Corporation</holder>
+     </copyright>
+     <copyright>
+       <year>2012</year>
+       <holder>Laurent Pinchart</holder>
+     </copyright>
+     <copyright>
+       <year>2015</year>
+       <holder>Lukas Wunner</holder>
+     </copyright>
+     <legalnotice>
+       <para>
+       The contents of this file may be used under the terms of the GNU
+       General Public License version 2 (the "GPL") as distributed in
+       the kernel source COPYING file.
+       </para>
+     </legalnotice>
+     <revhistory>
+       <!-- Put document revisions here, newest first. -->
+       <revision>
+       <revnumber>1.0</revnumber>
+       <date>2012-07-13</date>
+       <authorinitials>LP</authorinitials>
+       <revremark>Added extensive documentation about driver internals.
+       </revremark>
+       </revision>
+       <revision>
+       <revnumber>1.1</revnumber>
+       <date>2015-10-11</date>
+       <authorinitials>LW</authorinitials>
+       <revremark>Added vga_switcheroo documentation.
+       </revremark>
+       </revision>
+     </revhistory>
+   </bookinfo>
+ <toc></toc>
+ <part id="drmCore">
+   <title>DRM Core</title>
+   <partintro>
+     <para>
+       This first part of the GPU Driver Developer's Guide documents core DRM
+       code, helper libraries for writing drivers and generic userspace
+       interfaces exposed by DRM drivers.
+     </para>
+   </partintro>
+   <chapter id="drmIntroduction">
+     <title>Introduction</title>
+     <para>
+       The Linux DRM layer contains code intended to support the needs
+       of complex graphics devices, usually containing programmable
+       pipelines well suited to 3D graphics acceleration.  Graphics
+       drivers in the kernel may make use of DRM functions to make
+       tasks like memory management, interrupt handling and DMA easier,
+       and provide a uniform interface to applications.
+     </para>
+     <para>
+       A note on versions: this guide covers features found in the DRM
+       tree, including the TTM memory manager, output configuration and
+       mode setting, and the new vblank internals, in addition to all
+       the regular features found in current kernels.
+     </para>
+     <para>
+       [Insert diagram of typical DRM stack here]
+     </para>
+   </chapter>
+   <!-- Internals -->
+   <chapter id="drmInternals">
+     <title>DRM Internals</title>
+     <para>
+       This chapter documents DRM internals relevant to driver authors
+       and developers working to add support for the latest features to
+       existing drivers.
+     </para>
+     <para>
+       First, we go over some typical driver initialization
+       requirements, like setting up command buffers, creating an
+       initial output configuration, and initializing core services.
+       Subsequent sections cover core internals in more detail,
+       providing implementation notes and examples.
+     </para>
+     <para>
+       The DRM layer provides several services to graphics drivers,
+       many of them driven by the application interfaces it provides
+       through libdrm, the library that wraps most of the DRM ioctls.
+       These include vblank event handling, memory
+       management, output management, framebuffer management, command
+       submission &amp; fencing, suspend/resume support, and DMA
+       services.
+     </para>
+   <!-- Internals: driver init -->
+   <sect1>
+     <title>Driver Initialization</title>
+     <para>
+       At the core of every DRM driver is a <structname>drm_driver</structname>
+       structure. Drivers typically statically initialize a drm_driver structure,
+       and then pass it to <function>drm_dev_alloc()</function> to allocate a
+       device instance. After the device instance is fully initialized it can be
+       registered (which makes it accessible from userspace) using
+       <function>drm_dev_register()</function>.
+     </para>
+     <para>
+       The <structname>drm_driver</structname> structure contains static
+       information that describes the driver and features it supports, and
+       pointers to methods that the DRM core will call to implement the DRM API.
+       We will first go through the <structname>drm_driver</structname> static
+       information fields, and will then describe individual operations in
+       details as they get used in later sections.
+     </para>
+     <sect2>
+       <title>Driver Information</title>
+       <sect3>
+         <title>Driver Features</title>
+         <para>
+           Drivers inform the DRM core about their requirements and supported
+           features by setting appropriate flags in the
+           <structfield>driver_features</structfield> field. Since those flags
+           influence the DRM core behaviour since registration time, most of them
+           must be set to registering the <structname>drm_driver</structname>
+           instance.
+         </para>
+         <synopsis>u32 driver_features;</synopsis>
+         <variablelist>
+           <title>Driver Feature Flags</title>
+           <varlistentry>
+             <term>DRIVER_USE_AGP</term>
+             <listitem><para>
+               Driver uses AGP interface, the DRM core will manage AGP resources.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_REQUIRE_AGP</term>
+             <listitem><para>
+               Driver needs AGP interface to function. AGP initialization failure
+               will become a fatal error.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_PCI_DMA</term>
+             <listitem><para>
+               Driver is capable of PCI DMA, mapping of PCI DMA buffers to
+               userspace will be enabled. Deprecated.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_SG</term>
+             <listitem><para>
+               Driver can perform scatter/gather DMA, allocation and mapping of
+               scatter/gather buffers will be enabled. Deprecated.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_HAVE_DMA</term>
+             <listitem><para>
+               Driver supports DMA, the userspace DMA API will be supported.
+               Deprecated.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_HAVE_IRQ</term><term>DRIVER_IRQ_SHARED</term>
+             <listitem><para>
+               DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler
+               managed by the DRM Core. The core will support simple IRQ handler
+               installation when the flag is set. The installation process is
+               described in <xref linkend="drm-irq-registration"/>.</para>
+               <para>DRIVER_IRQ_SHARED indicates whether the device &amp; handler
+               support shared IRQs (note that this is required of PCI  drivers).
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_GEM</term>
+             <listitem><para>
+               Driver use the GEM memory manager.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_MODESET</term>
+             <listitem><para>
+               Driver supports mode setting interfaces (KMS).
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_PRIME</term>
+             <listitem><para>
+               Driver implements DRM PRIME buffer sharing.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_RENDER</term>
+             <listitem><para>
+               Driver supports dedicated render nodes.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRIVER_ATOMIC</term>
+             <listitem><para>
+               Driver supports atomic properties.  In this case the driver
+               must implement appropriate obj->atomic_get_property() vfuncs
+               for any modeset objects with driver specific properties.
+             </para></listitem>
+           </varlistentry>
+         </variablelist>
+       </sect3>
+       <sect3>
+         <title>Major, Minor and Patchlevel</title>
+         <synopsis>int major;
+ int minor;
+ int patchlevel;</synopsis>
+         <para>
+           The DRM core identifies driver versions by a major, minor and patch
+           level triplet. The information is printed to the kernel log at
+           initialization time and passed to userspace through the
+           DRM_IOCTL_VERSION ioctl.
+         </para>
+         <para>
+           The major and minor numbers are also used to verify the requested driver
+           API version passed to DRM_IOCTL_SET_VERSION. When the driver API changes
+           between minor versions, applications can call DRM_IOCTL_SET_VERSION to
+           select a specific version of the API. If the requested major isn't equal
+           to the driver major, or the requested minor is larger than the driver
+           minor, the DRM_IOCTL_SET_VERSION call will return an error. Otherwise
+           the driver's set_version() method will be called with the requested
+           version.
+         </para>
+       </sect3>
+       <sect3>
+         <title>Name, Description and Date</title>
+         <synopsis>char *name;
+ char *desc;
+ char *date;</synopsis>
+         <para>
+           The driver name is printed to the kernel log at initialization time,
+           used for IRQ registration and passed to userspace through
+           DRM_IOCTL_VERSION.
+         </para>
+         <para>
+           The driver description is a purely informative string passed to
+           userspace through the DRM_IOCTL_VERSION ioctl and otherwise unused by
+           the kernel.
+         </para>
+         <para>
+           The driver date, formatted as YYYYMMDD, is meant to identify the date of
+           the latest modification to the driver. However, as most drivers fail to
+           update it, its value is mostly useless. The DRM core prints it to the
+           kernel log at initialization time and passes it to userspace through the
+           DRM_IOCTL_VERSION ioctl.
+         </para>
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>Device Instance and Driver Handling</title>
+ !Pdrivers/gpu/drm/drm_drv.c driver instance overview
+ !Edrivers/gpu/drm/drm_drv.c
+     </sect2>
+     <sect2>
+       <title>Driver Load</title>
+       <sect3 id="drm-irq-registration">
+         <title>IRQ Registration</title>
+         <para>
+           The DRM core tries to facilitate IRQ handler registration and
+           unregistration by providing <function>drm_irq_install</function> and
+           <function>drm_irq_uninstall</function> functions. Those functions only
+           support a single interrupt per device, devices that use more than one
+           IRQs need to be handled manually.
+         </para>
+         <sect4>
+           <title>Managed IRQ Registration</title>
+           <para>
+             <function>drm_irq_install</function> starts by calling the
+             <methodname>irq_preinstall</methodname> driver operation. The operation
+             is optional and must make sure that the interrupt will not get fired by
+             clearing all pending interrupt flags or disabling the interrupt.
+           </para>
+           <para>
+             The passed-in IRQ will then be requested by a call to
+             <function>request_irq</function>. If the DRIVER_IRQ_SHARED driver
+             feature flag is set, a shared (IRQF_SHARED) IRQ handler will be
+             requested.
+           </para>
+           <para>
+             The IRQ handler function must be provided as the mandatory irq_handler
+             driver operation. It will get passed directly to
+             <function>request_irq</function> and thus has the same prototype as all
+             IRQ handlers. It will get called with a pointer to the DRM device as the
+             second argument.
+           </para>
+           <para>
+             Finally the function calls the optional
+             <methodname>irq_postinstall</methodname> driver operation. The operation
+             usually enables interrupts (excluding the vblank interrupt, which is
+             enabled separately), but drivers may choose to enable/disable interrupts
+             at a different time.
+           </para>
+           <para>
+             <function>drm_irq_uninstall</function> is similarly used to uninstall an
+             IRQ handler. It starts by waking up all processes waiting on a vblank
+             interrupt to make sure they don't hang, and then calls the optional
+             <methodname>irq_uninstall</methodname> driver operation. The operation
+             must disable all hardware interrupts. Finally the function frees the IRQ
+             by calling <function>free_irq</function>.
+           </para>
+         </sect4>
+         <sect4>
+           <title>Manual IRQ Registration</title>
+           <para>
+             Drivers that require multiple interrupt handlers can't use the managed
+             IRQ registration functions. In that case IRQs must be registered and
+             unregistered manually (usually with the <function>request_irq</function>
+             and <function>free_irq</function> functions, or their devm_* equivalent).
+           </para>
+           <para>
+             When manually registering IRQs, drivers must not set the DRIVER_HAVE_IRQ
+             driver feature flag, and must not provide the
+           <methodname>irq_handler</methodname> driver operation. They must set the
+           <structname>drm_device</structname> <structfield>irq_enabled</structfield>
+           field to 1 upon registration of the IRQs, and clear it to 0 after
+           unregistering the IRQs.
+           </para>
+         </sect4>
+       </sect3>
+       <sect3>
+         <title>Memory Manager Initialization</title>
+         <para>
+           Every DRM driver requires a memory manager which must be initialized at
+           load time. DRM currently contains two memory managers, the Translation
+           Table Manager (TTM) and the Graphics Execution Manager (GEM).
+           This document describes the use of the GEM memory manager only. See
+           <xref linkend="drm-memory-management"/> for details.
+         </para>
+       </sect3>
+       <sect3>
+         <title>Miscellaneous Device Configuration</title>
+         <para>
+           Another task that may be necessary for PCI devices during configuration
+           is mapping the video BIOS. On many devices, the VBIOS describes device
+           configuration, LCD panel timings (if any), and contains flags indicating
+           device state. Mapping the BIOS can be done using the pci_map_rom() call,
+           a convenience function that takes care of mapping the actual ROM,
+           whether it has been shadowed into memory (typically at address 0xc0000)
+           or exists on the PCI device in the ROM BAR. Note that after the ROM has
+           been mapped and any necessary information has been extracted, it should
+           be unmapped; on many devices, the ROM address decoder is shared with
+           other BARs, so leaving it mapped could cause undesired behaviour like
+           hangs or memory corruption.
+   <!--!Fdrivers/pci/rom.c pci_map_rom-->
+         </para>
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>Bus-specific Device Registration and PCI Support</title>
+       <para>
+         A number of functions are provided to help with device registration.
+       The functions deal with PCI and platform devices respectively and are
+       only provided for historical reasons. These are all deprecated and
+       shouldn't be used in new drivers. Besides that there's a few
+       helpers for pci drivers.
+       </para>
+ !Edrivers/gpu/drm/drm_pci.c
+ !Edrivers/gpu/drm/drm_platform.c
+     </sect2>
+   </sect1>
+   <!-- Internals: memory management -->
+   <sect1 id="drm-memory-management">
+     <title>Memory management</title>
+     <para>
+       Modern Linux systems require large amount of graphics memory to store
+       frame buffers, textures, vertices and other graphics-related data. Given
+       the very dynamic nature of many of that data, managing graphics memory
+       efficiently is thus crucial for the graphics stack and plays a central
+       role in the DRM infrastructure.
+     </para>
+     <para>
+       The DRM core includes two memory managers, namely Translation Table Maps
+       (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory
+       manager to be developed and tried to be a one-size-fits-them all
+       solution. It provides a single userspace API to accommodate the need of
+       all hardware, supporting both Unified Memory Architecture (UMA) devices
+       and devices with dedicated video RAM (i.e. most discrete video cards).
+       This resulted in a large, complex piece of code that turned out to be
+       hard to use for driver development.
+     </para>
+     <para>
+       GEM started as an Intel-sponsored project in reaction to TTM's
+       complexity. Its design philosophy is completely different: instead of
+       providing a solution to every graphics memory-related problems, GEM
+       identified common code between drivers and created a support library to
+       share it. GEM has simpler initialization and execution requirements than
+       TTM, but has no video RAM management capabilities and is thus limited to
+       UMA devices.
+     </para>
+     <sect2>
+       <title>The Translation Table Manager (TTM)</title>
+       <para>
+         TTM design background and information belongs here.
+       </para>
+       <sect3>
+         <title>TTM initialization</title>
+         <warning><para>This section is outdated.</para></warning>
+         <para>
+           Drivers wishing to support TTM must fill out a drm_bo_driver
+           structure. The structure contains several fields with function
+           pointers for initializing the TTM, allocating and freeing memory,
+           waiting for command completion and fence synchronization, and memory
+           migration. See the radeon_ttm.c file for an example of usage.
+         </para>
+         <para>
+           The ttm_global_reference structure is made up of several fields:
+         </para>
+         <programlisting>
+           struct ttm_global_reference {
+                   enum ttm_global_types global_type;
+                   size_t size;
+                   void *object;
+                   int (*init) (struct ttm_global_reference *);
+                   void (*release) (struct ttm_global_reference *);
+           };
+         </programlisting>
+         <para>
+           There should be one global reference structure for your memory
+           manager as a whole, and there will be others for each object
+           created by the memory manager at runtime.  Your global TTM should
+           have a type of TTM_GLOBAL_TTM_MEM.  The size field for the global
+           object should be sizeof(struct ttm_mem_global), and the init and
+           release hooks should point at your driver-specific init and
+           release routines, which probably eventually call
+           ttm_mem_global_init and ttm_mem_global_release, respectively.
+         </para>
+         <para>
+           Once your global TTM accounting structure is set up and initialized
+           by calling ttm_global_item_ref() on it,
+           you need to create a buffer object TTM to
+           provide a pool for buffer object allocation by clients and the
+           kernel itself.  The type of this object should be TTM_GLOBAL_TTM_BO,
+           and its size should be sizeof(struct ttm_bo_global).  Again,
+           driver-specific init and release functions may be provided,
+           likely eventually calling ttm_bo_global_init() and
+           ttm_bo_global_release(), respectively.  Also, like the previous
+           object, ttm_global_item_ref() is used to create an initial reference
+           count for the TTM, which will call your initialization function.
+         </para>
+       </sect3>
+     </sect2>
+     <sect2 id="drm-gem">
+       <title>The Graphics Execution Manager (GEM)</title>
+       <para>
+         The GEM design approach has resulted in a memory manager that doesn't
+         provide full coverage of all (or even all common) use cases in its
+         userspace or kernel API. GEM exposes a set of standard memory-related
+         operations to userspace and a set of helper functions to drivers, and let
+         drivers implement hardware-specific operations with their own private API.
+       </para>
+       <para>
+         The GEM userspace API is described in the
+         <ulink url="http://lwn.net/Articles/283798/"><citetitle>GEM - the Graphics
+         Execution Manager</citetitle></ulink> article on LWN. While slightly
+         outdated, the document provides a good overview of the GEM API principles.
+         Buffer allocation and read and write operations, described as part of the
+         common GEM API, are currently implemented using driver-specific ioctls.
+       </para>
+       <para>
+         GEM is data-agnostic. It manages abstract buffer objects without knowing
+         what individual buffers contain. APIs that require knowledge of buffer
+         contents or purpose, such as buffer allocation or synchronization
+         primitives, are thus outside of the scope of GEM and must be implemented
+         using driver-specific ioctls.
+       </para>
+       <para>
+         On a fundamental level, GEM involves several operations:
+         <itemizedlist>
+           <listitem>Memory allocation and freeing</listitem>
+           <listitem>Command execution</listitem>
+           <listitem>Aperture management at command execution time</listitem>
+         </itemizedlist>
+         Buffer object allocation is relatively straightforward and largely
+         provided by Linux's shmem layer, which provides memory to back each
+         object.
+       </para>
+       <para>
+         Device-specific operations, such as command execution, pinning, buffer
+         read &amp; write, mapping, and domain ownership transfers are left to
+         driver-specific ioctls.
+       </para>
+       <sect3>
+         <title>GEM Initialization</title>
+         <para>
+           Drivers that use GEM must set the DRIVER_GEM bit in the struct
+           <structname>drm_driver</structname>
+           <structfield>driver_features</structfield> field. The DRM core will
+           then automatically initialize the GEM core before calling the
+           <methodname>load</methodname> operation. Behind the scene, this will
+           create a DRM Memory Manager object which provides an address space
+           pool for object allocation.
+         </para>
+         <para>
+           In a KMS configuration, drivers need to allocate and initialize a
+           command ring buffer following core GEM initialization if required by
+           the hardware. UMA devices usually have what is called a "stolen"
+           memory region, which provides space for the initial framebuffer and
+           large, contiguous memory regions required by the device. This space is
+           typically not managed by GEM, and must be initialized separately into
+           its own DRM MM object.
+         </para>
+       </sect3>
+       <sect3>
+         <title>GEM Objects Creation</title>
+         <para>
+           GEM splits creation of GEM objects and allocation of the memory that
+           backs them in two distinct operations.
+         </para>
+         <para>
+           GEM objects are represented by an instance of struct
+           <structname>drm_gem_object</structname>. Drivers usually need to extend
+           GEM objects with private information and thus create a driver-specific
+           GEM object structure type that embeds an instance of struct
+           <structname>drm_gem_object</structname>.
+         </para>
+         <para>
+           To create a GEM object, a driver allocates memory for an instance of its
+           specific GEM object type and initializes the embedded struct
+           <structname>drm_gem_object</structname> with a call to
+           <function>drm_gem_object_init</function>. The function takes a pointer to
+           the DRM device, a pointer to the GEM object and the buffer object size
+           in bytes.
+         </para>
+         <para>
+           GEM uses shmem to allocate anonymous pageable memory.
+           <function>drm_gem_object_init</function> will create an shmfs file of
+           the requested size and store it into the struct
+           <structname>drm_gem_object</structname> <structfield>filp</structfield>
+           field. The memory is used as either main storage for the object when the
+           graphics hardware uses system memory directly or as a backing store
+           otherwise.
+         </para>
+         <para>
+           Drivers are responsible for the actual physical pages allocation by
+           calling <function>shmem_read_mapping_page_gfp</function> for each page.
+           Note that they can decide to allocate pages when initializing the GEM
+           object, or to delay allocation until the memory is needed (for instance
+           when a page fault occurs as a result of a userspace memory access or
+           when the driver needs to start a DMA transfer involving the memory).
+         </para>
+         <para>
+           Anonymous pageable memory allocation is not always desired, for instance
+           when the hardware requires physically contiguous system memory as is
+           often the case in embedded devices. Drivers can create GEM objects with
+           no shmfs backing (called private GEM objects) by initializing them with
+           a call to <function>drm_gem_private_object_init</function> instead of
+           <function>drm_gem_object_init</function>. Storage for private GEM
+           objects must be managed by drivers.
+         </para>
+         <para>
+           Drivers that do not need to extend GEM objects with private information
+           can call the <function>drm_gem_object_alloc</function> function to
+           allocate and initialize a struct <structname>drm_gem_object</structname>
+           instance. The GEM core will call the optional driver
+           <methodname>gem_init_object</methodname> operation after initializing
+           the GEM object with <function>drm_gem_object_init</function>.
+           <synopsis>int (*gem_init_object) (struct drm_gem_object *obj);</synopsis>
+         </para>
+         <para>
+           No alloc-and-init function exists for private GEM objects.
+         </para>
+       </sect3>
+       <sect3>
+         <title>GEM Objects Lifetime</title>
+         <para>
+           All GEM objects are reference-counted by the GEM core. References can be
+           acquired and release by <function>calling drm_gem_object_reference</function>
+           and <function>drm_gem_object_unreference</function> respectively. The
+           caller must hold the <structname>drm_device</structname>
+           <structfield>struct_mutex</structfield> lock. As a convenience, GEM
+           provides the <function>drm_gem_object_reference_unlocked</function> and
+           <function>drm_gem_object_unreference_unlocked</function> functions that
+           can be called without holding the lock.
+         </para>
+         <para>
+           When the last reference to a GEM object is released the GEM core calls
+           the <structname>drm_driver</structname>
+           <methodname>gem_free_object</methodname> operation. That operation is
+           mandatory for GEM-enabled drivers and must free the GEM object and all
+           associated resources.
+         </para>
+         <para>
+           <synopsis>void (*gem_free_object) (struct drm_gem_object *obj);</synopsis>
+           Drivers are responsible for freeing all GEM object resources, including
+           the resources created by the GEM core. If an mmap offset has been
+           created for the object (in which case
+           <structname>drm_gem_object</structname>::<structfield>map_list</structfield>::<structfield>map</structfield>
+           is not NULL) it must be freed by a call to
+           <function>drm_gem_free_mmap_offset</function>. The shmfs backing store
+           must be released by calling <function>drm_gem_object_release</function>
+           (that function can safely be called if no shmfs backing store has been
+           created).
+         </para>
+       </sect3>
+       <sect3>
+         <title>GEM Objects Naming</title>
+         <para>
+           Communication between userspace and the kernel refers to GEM objects
+           using local handles, global names or, more recently, file descriptors.
+           All of those are 32-bit integer values; the usual Linux kernel limits
+           apply to the file descriptors.
+         </para>
+         <para>
+           GEM handles are local to a DRM file. Applications get a handle to a GEM
+           object through a driver-specific ioctl, and can use that handle to refer
+           to the GEM object in other standard or driver-specific ioctls. Closing a
+           DRM file handle frees all its GEM handles and dereferences the
+           associated GEM objects.
+         </para>
+         <para>
+           To create a handle for a GEM object drivers call
+           <function>drm_gem_handle_create</function>. The function takes a pointer
+           to the DRM file and the GEM object and returns a locally unique handle.
+           When the handle is no longer needed drivers delete it with a call to
+           <function>drm_gem_handle_delete</function>. Finally the GEM object
+           associated with a handle can be retrieved by a call to
+           <function>drm_gem_object_lookup</function>.
+         </para>
+         <para>
+           Handles don't take ownership of GEM objects, they only take a reference
+           to the object that will be dropped when the handle is destroyed. To
+           avoid leaking GEM objects, drivers must make sure they drop the
+           reference(s) they own (such as the initial reference taken at object
+           creation time) as appropriate, without any special consideration for the
+           handle. For example, in the particular case of combined GEM object and
+           handle creation in the implementation of the
+           <methodname>dumb_create</methodname> operation, drivers must drop the
+           initial reference to the GEM object before returning the handle.
+         </para>
+         <para>
+           GEM names are similar in purpose to handles but are not local to DRM
+           files. They can be passed between processes to reference a GEM object
+           globally. Names can't be used directly to refer to objects in the DRM
+           API, applications must convert handles to names and names to handles
+           using the DRM_IOCTL_GEM_FLINK and DRM_IOCTL_GEM_OPEN ioctls
+           respectively. The conversion is handled by the DRM core without any
+           driver-specific support.
+         </para>
+         <para>
+           GEM also supports buffer sharing with dma-buf file descriptors through
+           PRIME. GEM-based drivers must use the provided helpers functions to
+           implement the exporting and importing correctly. See <xref linkend="drm-prime-support" />.
+           Since sharing file descriptors is inherently more secure than the
+           easily guessable and global GEM names it is the preferred buffer
+           sharing mechanism. Sharing buffers through GEM names is only supported
+           for legacy userspace. Furthermore PRIME also allows cross-device
+           buffer sharing since it is based on dma-bufs.
+         </para>
+       </sect3>
+       <sect3 id="drm-gem-objects-mapping">
+         <title>GEM Objects Mapping</title>
+         <para>
+           Because mapping operations are fairly heavyweight GEM favours
+           read/write-like access to buffers, implemented through driver-specific
+           ioctls, over mapping buffers to userspace. However, when random access
+           to the buffer is needed (to perform software rendering for instance),
+           direct access to the object can be more efficient.
+         </para>
+         <para>
+           The mmap system call can't be used directly to map GEM objects, as they
+           don't have their own file handle. Two alternative methods currently
+           co-exist to map GEM objects to userspace. The first method uses a
+           driver-specific ioctl to perform the mapping operation, calling
+           <function>do_mmap</function> under the hood. This is often considered
+           dubious, seems to be discouraged for new GEM-enabled drivers, and will
+           thus not be described here.
+         </para>
+         <para>
+           The second method uses the mmap system call on the DRM file handle.
+           <synopsis>void *mmap(void *addr, size_t length, int prot, int flags, int fd,
+              off_t offset);</synopsis>
+           DRM identifies the GEM object to be mapped by a fake offset passed
+           through the mmap offset argument. Prior to being mapped, a GEM object
+           must thus be associated with a fake offset. To do so, drivers must call
+           <function>drm_gem_create_mmap_offset</function> on the object. The
+           function allocates a fake offset range from a pool and stores the
+           offset divided by PAGE_SIZE in
+           <literal>obj-&gt;map_list.hash.key</literal>. Care must be taken not to
+           call <function>drm_gem_create_mmap_offset</function> if a fake offset
+           has already been allocated for the object. This can be tested by
+           <literal>obj-&gt;map_list.map</literal> being non-NULL.
+         </para>
+         <para>
+           Once allocated, the fake offset value
+           (<literal>obj-&gt;map_list.hash.key &lt;&lt; PAGE_SHIFT</literal>)
+           must be passed to the application in a driver-specific way and can then
+           be used as the mmap offset argument.
+         </para>
+         <para>
+           The GEM core provides a helper method <function>drm_gem_mmap</function>
+           to handle object mapping. The method can be set directly as the mmap
+           file operation handler. It will look up the GEM object based on the
+           offset value and set the VMA operations to the
+           <structname>drm_driver</structname> <structfield>gem_vm_ops</structfield>
+           field. Note that <function>drm_gem_mmap</function> doesn't map memory to
+           userspace, but relies on the driver-provided fault handler to map pages
+           individually.
+         </para>
+         <para>
+           To use <function>drm_gem_mmap</function>, drivers must fill the struct
+           <structname>drm_driver</structname> <structfield>gem_vm_ops</structfield>
+           field with a pointer to VM operations.
+         </para>
+         <para>
+           <synopsis>struct vm_operations_struct *gem_vm_ops
+   struct vm_operations_struct {
+           void (*open)(struct vm_area_struct * area);
+           void (*close)(struct vm_area_struct * area);
+           int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
+   };</synopsis>
+         </para>
+         <para>
+           The <methodname>open</methodname> and <methodname>close</methodname>
+           operations must update the GEM object reference count. Drivers can use
+           the <function>drm_gem_vm_open</function> and
+           <function>drm_gem_vm_close</function> helper functions directly as open
+           and close handlers.
+         </para>
+         <para>
+           The fault operation handler is responsible for mapping individual pages
+           to userspace when a page fault occurs. Depending on the memory
+           allocation scheme, drivers can allocate pages at fault time, or can
+           decide to allocate memory for the GEM object at the time the object is
+           created.
+         </para>
+         <para>
+           Drivers that want to map the GEM object upfront instead of handling page
+           faults can implement their own mmap file operation handler.
+         </para>
+       </sect3>
+       <sect3>
+         <title>Memory Coherency</title>
+         <para>
+           When mapped to the device or used in a command buffer, backing pages
+           for an object are flushed to memory and marked write combined so as to
+           be coherent with the GPU. Likewise, if the CPU accesses an object
+           after the GPU has finished rendering to the object, then the object
+           must be made coherent with the CPU's view of memory, usually involving
+           GPU cache flushing of various kinds. This core CPU&lt;-&gt;GPU
+           coherency management is provided by a device-specific ioctl, which
+           evaluates an object's current domain and performs any necessary
+           flushing or synchronization to put the object into the desired
+           coherency domain (note that the object may be busy, i.e. an active
+           render target; in that case, setting the domain blocks the client and
+           waits for rendering to complete before performing any necessary
+           flushing operations).
+         </para>
+       </sect3>
+       <sect3>
+         <title>Command Execution</title>
+         <para>
+           Perhaps the most important GEM function for GPU devices is providing a
+           command execution interface to clients. Client programs construct
+           command buffers containing references to previously allocated memory
+           objects, and then submit them to GEM. At that point, GEM takes care to
+           bind all the objects into the GTT, execute the buffer, and provide
+           necessary synchronization between clients accessing the same buffers.
+           This often involves evicting some objects from the GTT and re-binding
+           others (a fairly expensive operation), and providing relocation
+           support which hides fixed GTT offsets from clients. Clients must take
+           care not to submit command buffers that reference more objects than
+           can fit in the GTT; otherwise, GEM will reject them and no rendering
+           will occur. Similarly, if several objects in the buffer require fence
+           registers to be allocated for correct rendering (e.g. 2D blits on
+           pre-965 chips), care must be taken not to require more fence registers
+           than are available to the client. Such resource management should be
+           abstracted from the client in libdrm.
+         </para>
+       </sect3>
+       <sect3>
+         <title>GEM Function Reference</title>
+ !Edrivers/gpu/drm/drm_gem.c
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>VMA Offset Manager</title>
+ !Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager
+ !Edrivers/gpu/drm/drm_vma_manager.c
+ !Iinclude/drm/drm_vma_manager.h
+     </sect2>
+     <sect2 id="drm-prime-support">
+       <title>PRIME Buffer Sharing</title>
+       <para>
+         PRIME is the cross device buffer sharing framework in drm, originally
+         created for the OPTIMUS range of multi-gpu platforms. To userspace
+         PRIME buffers are dma-buf based file descriptors.
+       </para>
+       <sect3>
+         <title>Overview and Driver Interface</title>
+         <para>
+           Similar to GEM global names, PRIME file descriptors are
+           also used to share buffer objects across processes. They offer
+           additional security: as file descriptors must be explicitly sent over
+           UNIX domain sockets to be shared between applications, they can't be
+           guessed like the globally unique GEM names.
+         </para>
+         <para>
+           Drivers that support the PRIME
+           API must set the DRIVER_PRIME bit in the struct
+           <structname>drm_driver</structname>
+           <structfield>driver_features</structfield> field, and implement the
+           <methodname>prime_handle_to_fd</methodname> and
+           <methodname>prime_fd_to_handle</methodname> operations.
+         </para>
+         <para>
+           <synopsis>int (*prime_handle_to_fd)(struct drm_device *dev,
+                           struct drm_file *file_priv, uint32_t handle,
+                           uint32_t flags, int *prime_fd);
+ int (*prime_fd_to_handle)(struct drm_device *dev,
+                           struct drm_file *file_priv, int prime_fd,
+                           uint32_t *handle);</synopsis>
+             Those two operations convert a handle to a PRIME file descriptor and
+             vice versa. Drivers must use the kernel dma-buf buffer sharing framework
+             to manage the PRIME file descriptors. Similar to the mode setting
+             API PRIME is agnostic to the underlying buffer object manager, as
+             long as handles are 32bit unsigned integers.
+           </para>
+           <para>
+             While non-GEM drivers must implement the operations themselves, GEM
+             drivers must use the <function>drm_gem_prime_handle_to_fd</function>
+             and <function>drm_gem_prime_fd_to_handle</function> helper functions.
+             Those helpers rely on the driver
+             <methodname>gem_prime_export</methodname> and
+             <methodname>gem_prime_import</methodname> operations to create a dma-buf
+             instance from a GEM object (dma-buf exporter role) and to create a GEM
+             object from a dma-buf instance (dma-buf importer role).
+           </para>
+           <para>
+             <synopsis>struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
+                              struct drm_gem_object *obj,
+                              int flags);
+ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
+                                             struct dma_buf *dma_buf);</synopsis>
+             These two operations are mandatory for GEM drivers that support
+             PRIME.
+           </para>
+         </sect3>
+       <sect3>
+         <title>PRIME Helper Functions</title>
+ !Pdrivers/gpu/drm/drm_prime.c PRIME Helpers
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>PRIME Function References</title>
+ !Edrivers/gpu/drm/drm_prime.c
+     </sect2>
+     <sect2>
+       <title>DRM MM Range Allocator</title>
+       <sect3>
+         <title>Overview</title>
+ !Pdrivers/gpu/drm/drm_mm.c Overview
+       </sect3>
+       <sect3>
+         <title>LRU Scan/Eviction Support</title>
+ !Pdrivers/gpu/drm/drm_mm.c lru scan roaster
+       </sect3>
+       </sect2>
+     <sect2>
+       <title>DRM MM Range Allocator Function References</title>
+ !Edrivers/gpu/drm/drm_mm.c
+ !Iinclude/drm/drm_mm.h
+     </sect2>
+     <sect2>
+       <title>CMA Helper Functions Reference</title>
+ !Pdrivers/gpu/drm/drm_gem_cma_helper.c cma helpers
+ !Edrivers/gpu/drm/drm_gem_cma_helper.c
+ !Iinclude/drm/drm_gem_cma_helper.h
+     </sect2>
+   </sect1>
+   <!-- Internals: mode setting -->
+   <sect1 id="drm-mode-setting">
+     <title>Mode Setting</title>
+     <para>
+       Drivers must initialize the mode setting core by calling
+       <function>drm_mode_config_init</function> on the DRM device. The function
+       initializes the <structname>drm_device</structname>
+       <structfield>mode_config</structfield> field and never fails. Once done,
+       mode configuration must be setup by initializing the following fields.
+     </para>
+     <itemizedlist>
+       <listitem>
+         <synopsis>int min_width, min_height;
+ int max_width, max_height;</synopsis>
+         <para>
+         Minimum and maximum width and height of the frame buffers in pixel
+         units.
+       </para>
+       </listitem>
+       <listitem>
+         <synopsis>struct drm_mode_config_funcs *funcs;</synopsis>
+       <para>Mode setting functions.</para>
+       </listitem>
+     </itemizedlist>
+     <sect2>
+       <title>Display Modes Function Reference</title>
+ !Iinclude/drm/drm_modes.h
+ !Edrivers/gpu/drm/drm_modes.c
+     </sect2>
+     <sect2>
+       <title>Atomic Mode Setting Function Reference</title>
+ !Edrivers/gpu/drm/drm_atomic.c
+     </sect2>
+     <sect2>
+       <title>Frame Buffer Creation</title>
+       <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
+                                    struct drm_file *file_priv,
+                                    struct drm_mode_fb_cmd2 *mode_cmd);</synopsis>
+       <para>
+         Frame buffers are abstract memory objects that provide a source of
+         pixels to scanout to a CRTC. Applications explicitly request the
+         creation of frame buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and
+         receive an opaque handle that can be passed to the KMS CRTC control,
+         plane configuration and page flip functions.
+       </para>
+       <para>
+         Frame buffers rely on the underneath memory manager for low-level memory
+         operations. When creating a frame buffer applications pass a memory
+         handle (or a list of memory handles for multi-planar formats) through
+       the <parameter>drm_mode_fb_cmd2</parameter> argument. For drivers using
+       GEM as their userspace buffer management interface this would be a GEM
+       handle.  Drivers are however free to use their own backing storage object
+       handles, e.g. vmwgfx directly exposes special TTM handles to userspace
+       and so expects TTM handles in the create ioctl and not GEM handles.
+       </para>
+       <para>
+         Drivers must first validate the requested frame buffer parameters passed
+         through the mode_cmd argument. In particular this is where invalid
+         sizes, pixel formats or pitches can be caught.
+       </para>
+       <para>
+         If the parameters are deemed valid, drivers then create, initialize and
+         return an instance of struct <structname>drm_framebuffer</structname>.
+         If desired the instance can be embedded in a larger driver-specific
+       structure. Drivers must fill its <structfield>width</structfield>,
+       <structfield>height</structfield>, <structfield>pitches</structfield>,
+         <structfield>offsets</structfield>, <structfield>depth</structfield>,
+         <structfield>bits_per_pixel</structfield> and
+         <structfield>pixel_format</structfield> fields from the values passed
+         through the <parameter>drm_mode_fb_cmd2</parameter> argument. They
+         should call the <function>drm_helper_mode_fill_fb_struct</function>
+         helper function to do so.
+       </para>
+       <para>
+       The initialization of the new framebuffer instance is finalized with a
+       call to <function>drm_framebuffer_init</function> which takes a pointer
+       to DRM frame buffer operations (struct
+       <structname>drm_framebuffer_funcs</structname>). Note that this function
+       publishes the framebuffer and so from this point on it can be accessed
+       concurrently from other threads. Hence it must be the last step in the
+       driver's framebuffer initialization sequence. Frame buffer operations
+       are
+         <itemizedlist>
+           <listitem>
+             <synopsis>int (*create_handle)(struct drm_framebuffer *fb,
+                    struct drm_file *file_priv, unsigned int *handle);</synopsis>
+             <para>
+               Create a handle to the frame buffer underlying memory object. If
+               the frame buffer uses a multi-plane format, the handle will
+               reference the memory object associated with the first plane.
+             </para>
+             <para>
+               Drivers call <function>drm_gem_handle_create</function> to create
+               the handle.
+             </para>
+           </listitem>
+           <listitem>
+             <synopsis>void (*destroy)(struct drm_framebuffer *framebuffer);</synopsis>
+             <para>
+               Destroy the frame buffer object and frees all associated
+               resources. Drivers must call
+               <function>drm_framebuffer_cleanup</function> to free resources
+               allocated by the DRM core for the frame buffer object, and must
+               make sure to unreference all memory objects associated with the
+               frame buffer. Handles created by the
+               <methodname>create_handle</methodname> operation are released by
+               the DRM core.
+             </para>
+           </listitem>
+           <listitem>
+             <synopsis>int (*dirty)(struct drm_framebuffer *framebuffer,
+            struct drm_file *file_priv, unsigned flags, unsigned color,
+            struct drm_clip_rect *clips, unsigned num_clips);</synopsis>
+             <para>
+               This optional operation notifies the driver that a region of the
+               frame buffer has changed in response to a DRM_IOCTL_MODE_DIRTYFB
+               ioctl call.
+             </para>
+           </listitem>
+         </itemizedlist>
+       </para>
+       <para>
+       The lifetime of a drm framebuffer is controlled with a reference count,
+       drivers can grab additional references with
+       <function>drm_framebuffer_reference</function>and drop them
+       again with <function>drm_framebuffer_unreference</function>. For
+       driver-private framebuffers for which the last reference is never
+       dropped (e.g. for the fbdev framebuffer when the struct
+       <structname>drm_framebuffer</structname> is embedded into the fbdev
+       helper struct) drivers can manually clean up a framebuffer at module
+       unload time with
+       <function>drm_framebuffer_unregister_private</function>.
+       </para>
+     </sect2>
+     <sect2>
+       <title>Dumb Buffer Objects</title>
+       <para>
+       The KMS API doesn't standardize backing storage object creation and
+       leaves it to driver-specific ioctls. Furthermore actually creating a
+       buffer object even for GEM-based drivers is done through a
+       driver-specific ioctl - GEM only has a common userspace interface for
+       sharing and destroying objects. While not an issue for full-fledged
+       graphics stacks that include device-specific userspace components (in
+       libdrm for instance), this limit makes DRM-based early boot graphics
+       unnecessarily complex.
+       </para>
+       <para>
+         Dumb objects partly alleviate the problem by providing a standard
+         API to create dumb buffers suitable for scanout, which can then be used
+         to create KMS frame buffers.
+       </para>
+       <para>
+         To support dumb objects drivers must implement the
+         <methodname>dumb_create</methodname>,
+         <methodname>dumb_destroy</methodname> and
+         <methodname>dumb_map_offset</methodname> operations.
+       </para>
+       <itemizedlist>
+         <listitem>
+           <synopsis>int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev,
+                    struct drm_mode_create_dumb *args);</synopsis>
+           <para>
+             The <methodname>dumb_create</methodname> operation creates a driver
+           object (GEM or TTM handle) suitable for scanout based on the
+           width, height and depth from the struct
+           <structname>drm_mode_create_dumb</structname> argument. It fills the
+           argument's <structfield>handle</structfield>,
+           <structfield>pitch</structfield> and <structfield>size</structfield>
+           fields with a handle for the newly created object and its line
+             pitch and size in bytes.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev,
+                     uint32_t handle);</synopsis>
+           <para>
+             The <methodname>dumb_destroy</methodname> operation destroys a dumb
+             object created by <methodname>dumb_create</methodname>.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev,
+                        uint32_t handle, uint64_t *offset);</synopsis>
+           <para>
+             The <methodname>dumb_map_offset</methodname> operation associates an
+             mmap fake offset with the object given by the handle and returns
+             it. Drivers must use the
+             <function>drm_gem_create_mmap_offset</function> function to
+             associate the fake offset as described in
+             <xref linkend="drm-gem-objects-mapping"/>.
+           </para>
+         </listitem>
+       </itemizedlist>
+       <para>
+         Note that dumb objects may not be used for gpu acceleration, as has been
+       attempted on some ARM embedded platforms. Such drivers really must have
+       a hardware-specific ioctl to allocate suitable buffer objects.
+       </para>
+     </sect2>
+     <sect2>
+       <title>Output Polling</title>
+       <synopsis>void (*output_poll_changed)(struct drm_device *dev);</synopsis>
+       <para>
+         This operation notifies the driver that the status of one or more
+         connectors has changed. Drivers that use the fb helper can just call the
+         <function>drm_fb_helper_hotplug_event</function> function to handle this
+         operation.
+       </para>
+     </sect2>
+     <sect2>
+       <title>Locking</title>
+       <para>
+         Beside some lookup structures with their own locking (which is hidden
+       behind the interface functions) most of the modeset state is protected
+       by the <code>dev-&lt;mode_config.lock</code> mutex and additionally
+       per-crtc locks to allow cursor updates, pageflips and similar operations
+       to occur concurrently with background tasks like output detection.
+       Operations which cross domains like a full modeset always grab all
+       locks. Drivers there need to protect resources shared between crtcs with
+       additional locking. They also need to be careful to always grab the
+       relevant crtc locks if a modset functions touches crtc state, e.g. for
+       load detection (which does only grab the <code>mode_config.lock</code>
+       to allow concurrent screen updates on live crtcs).
+       </para>
+     </sect2>
+   </sect1>
+   <!-- Internals: kms initialization and cleanup -->
+   <sect1 id="drm-kms-init">
+     <title>KMS Initialization and Cleanup</title>
+     <para>
+       A KMS device is abstracted and exposed as a set of planes, CRTCs, encoders
+       and connectors. KMS drivers must thus create and initialize all those
+       objects at load time after initializing mode setting.
+     </para>
+     <sect2>
+       <title>CRTCs (struct <structname>drm_crtc</structname>)</title>
+       <para>
+         A CRTC is an abstraction representing a part of the chip that contains a
+       pointer to a scanout buffer. Therefore, the number of CRTCs available
+       determines how many independent scanout buffers can be active at any
+       given time. The CRTC structure contains several fields to support this:
+       a pointer to some video memory (abstracted as a frame buffer object), a
+       display mode, and an (x, y) offset into the video memory to support
+       panning or configurations where one piece of video memory spans multiple
+       CRTCs.
+       </para>
+       <sect3>
+         <title>CRTC Initialization</title>
+         <para>
+           A KMS device must create and register at least one struct
+           <structname>drm_crtc</structname> instance. The instance is allocated
+           and zeroed by the driver, possibly as part of a larger structure, and
+           registered with a call to <function>drm_crtc_init</function> with a
+           pointer to CRTC functions.
+         </para>
+       </sect3>
+       <sect3 id="drm-kms-crtcops">
+         <title>CRTC Operations</title>
+         <sect4>
+           <title>Set Configuration</title>
+           <synopsis>int (*set_config)(struct drm_mode_set *set);</synopsis>
+           <para>
+             Apply a new CRTC configuration to the device. The configuration
+             specifies a CRTC, a frame buffer to scan out from, a (x,y) position in
+             the frame buffer, a display mode and an array of connectors to drive
+             with the CRTC if possible.
+           </para>
+           <para>
+             If the frame buffer specified in the configuration is NULL, the driver
+             must detach all encoders connected to the CRTC and all connectors
+             attached to those encoders and disable them.
+           </para>
+           <para>
+             This operation is called with the mode config lock held.
+           </para>
+           <note><para>
+           Note that the drm core has no notion of restoring the mode setting
+           state after resume, since all resume handling is in the full
+           responsibility of the driver. The common mode setting helper library
+           though provides a helper which can be used for this:
+           <function>drm_helper_resume_force_mode</function>.
+           </para></note>
+         </sect4>
+         <sect4>
+           <title>Page Flipping</title>
+           <synopsis>int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                    struct drm_pending_vblank_event *event);</synopsis>
+           <para>
+             Schedule a page flip to the given frame buffer for the CRTC. This
+             operation is called with the mode config mutex held.
+           </para>
+           <para>
+             Page flipping is a synchronization mechanism that replaces the frame
+             buffer being scanned out by the CRTC with a new frame buffer during
+             vertical blanking, avoiding tearing. When an application requests a page
+             flip the DRM core verifies that the new frame buffer is large enough to
+             be scanned out by  the CRTC in the currently configured mode and then
+             calls the CRTC <methodname>page_flip</methodname> operation with a
+             pointer to the new frame buffer.
+           </para>
+           <para>
+             The <methodname>page_flip</methodname> operation schedules a page flip.
+             Once any pending rendering targeting the new frame buffer has
+             completed, the CRTC will be reprogrammed to display that frame buffer
+             after the next vertical refresh. The operation must return immediately
+             without waiting for rendering or page flip to complete and must block
+             any new rendering to the frame buffer until the page flip completes.
+           </para>
+           <para>
+             If a page flip can be successfully scheduled the driver must set the
+             <code>drm_crtc-&gt;fb</code> field to the new framebuffer pointed to
+             by <code>fb</code>. This is important so that the reference counting
+             on framebuffers stays balanced.
+           </para>
+           <para>
+             If a page flip is already pending, the
+             <methodname>page_flip</methodname> operation must return
+             -<errorname>EBUSY</errorname>.
+           </para>
+           <para>
+             To synchronize page flip to vertical blanking the driver will likely
+             need to enable vertical blanking interrupts. It should call
+             <function>drm_vblank_get</function> for that purpose, and call
+             <function>drm_vblank_put</function> after the page flip completes.
+           </para>
+           <para>
+             If the application has requested to be notified when page flip completes
+             the <methodname>page_flip</methodname> operation will be called with a
+             non-NULL <parameter>event</parameter> argument pointing to a
+             <structname>drm_pending_vblank_event</structname> instance. Upon page
+             flip completion the driver must call <methodname>drm_send_vblank_event</methodname>
+             to fill in the event and send to wake up any waiting processes.
+             This can be performed with
+             <programlisting><![CDATA[
+             spin_lock_irqsave(&dev->event_lock, flags);
+             ...
+             drm_send_vblank_event(dev, pipe, event);
+             spin_unlock_irqrestore(&dev->event_lock, flags);
+             ]]></programlisting>
+           </para>
+           <note><para>
+             FIXME: Could drivers that don't need to wait for rendering to complete
+             just add the event to <literal>dev-&gt;vblank_event_list</literal> and
+             let the DRM core handle everything, as for "normal" vertical blanking
+             events?
+           </para></note>
+           <para>
+             While waiting for the page flip to complete, the
+             <literal>event-&gt;base.link</literal> list head can be used freely by
+             the driver to store the pending event in a driver-specific list.
+           </para>
+           <para>
+             If the file handle is closed before the event is signaled, drivers must
+             take care to destroy the event in their
+             <methodname>preclose</methodname> operation (and, if needed, call
+             <function>drm_vblank_put</function>).
+           </para>
+         </sect4>
+         <sect4>
+           <title>Miscellaneous</title>
+           <itemizedlist>
+             <listitem>
+               <synopsis>void (*set_property)(struct drm_crtc *crtc,
+                      struct drm_property *property, uint64_t value);</synopsis>
+               <para>
+                 Set the value of the given CRTC property to
+                 <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
+                 for more information about properties.
+               </para>
+             </listitem>
+             <listitem>
+               <synopsis>void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
+                         uint32_t start, uint32_t size);</synopsis>
+               <para>
+                 Apply a gamma table to the device. The operation is optional.
+               </para>
+             </listitem>
+             <listitem>
+               <synopsis>void (*destroy)(struct drm_crtc *crtc);</synopsis>
+               <para>
+                 Destroy the CRTC when not needed anymore. See
+                 <xref linkend="drm-kms-init"/>.
+               </para>
+             </listitem>
+           </itemizedlist>
+         </sect4>
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>Planes (struct <structname>drm_plane</structname>)</title>
+       <para>
+         A plane represents an image source that can be blended with or overlayed
+       on top of a CRTC during the scanout process. Planes are associated with
+       a frame buffer to crop a portion of the image memory (source) and
+       optionally scale it to a destination size. The result is then blended
+       with or overlayed on top of a CRTC.
+       </para>
+       <para>
+       The DRM core recognizes three types of planes:
+       <itemizedlist>
+         <listitem>
+         DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC.  Primary
+         planes are the planes operated upon by CRTC modesetting and flipping
+         operations described in <xref linkend="drm-kms-crtcops"/>.
+         </listitem>
+         <listitem>
+         DRM_PLANE_TYPE_CURSOR represents a "cursor" plane for a CRTC.  Cursor
+         planes are the planes operated upon by the DRM_IOCTL_MODE_CURSOR and
+         DRM_IOCTL_MODE_CURSOR2 ioctls.
+         </listitem>
+         <listitem>
+         DRM_PLANE_TYPE_OVERLAY represents all non-primary, non-cursor planes.
+         Some drivers refer to these types of planes as "sprites" internally.
+         </listitem>
+       </itemizedlist>
+       For compatibility with legacy userspace, only overlay planes are made
+       available to userspace by default.  Userspace clients may set the
+       DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate that
+       they wish to receive a universal plane list containing all plane types.
+       </para>
+       <sect3>
+         <title>Plane Initialization</title>
+         <para>
+           To create a plane, a KMS drivers allocates and
+           zeroes an instances of struct <structname>drm_plane</structname>
+           (possibly as part of a larger structure) and registers it with a call
+           to <function>drm_universal_plane_init</function>. The function takes a bitmask
+           of the CRTCs that can be associated with the plane, a pointer to the
+           plane functions, a list of format supported formats, and the type of
+           plane (primary, cursor, or overlay) being initialized.
+         </para>
+         <para>
+           Cursor and overlay planes are optional.  All drivers should provide
+           one primary plane per CRTC (although this requirement may change in
+           the future); drivers that do not wish to provide special handling for
+           primary planes may make use of the helper functions described in
+           <xref linkend="drm-kms-planehelpers"/> to create and register a
+           primary plane with standard capabilities.
+         </para>
+       </sect3>
+       <sect3>
+         <title>Plane Operations</title>
+         <itemizedlist>
+           <listitem>
+             <synopsis>int (*update_plane)(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,
+                         uint32_t src_w, uint32_t src_h);</synopsis>
+             <para>
+               Enable and configure the plane to use the given CRTC and frame buffer.
+             </para>
+             <para>
+               The source rectangle in frame buffer memory coordinates is given by
+               the <parameter>src_x</parameter>, <parameter>src_y</parameter>,
+               <parameter>src_w</parameter> and <parameter>src_h</parameter>
+               parameters (as 16.16 fixed point values). Devices that don't support
+               subpixel plane coordinates can ignore the fractional part.
+             </para>
+             <para>
+               The destination rectangle in CRTC coordinates is given by the
+               <parameter>crtc_x</parameter>, <parameter>crtc_y</parameter>,
+               <parameter>crtc_w</parameter> and <parameter>crtc_h</parameter>
+               parameters (as integer values). Devices scale the source rectangle to
+               the destination rectangle. If scaling is not supported, and the source
+               rectangle size doesn't match the destination rectangle size, the
+               driver must return a -<errorname>EINVAL</errorname> error.
+             </para>
+           </listitem>
+           <listitem>
+             <synopsis>int (*disable_plane)(struct drm_plane *plane);</synopsis>
+             <para>
+               Disable the plane. The DRM core calls this method in response to a
+               DRM_IOCTL_MODE_SETPLANE ioctl call with the frame buffer ID set to 0.
+               Disabled planes must not be processed by the CRTC.
+             </para>
+           </listitem>
+           <listitem>
+             <synopsis>void (*destroy)(struct drm_plane *plane);</synopsis>
+             <para>
+               Destroy the plane when not needed anymore. See
+               <xref linkend="drm-kms-init"/>.
+             </para>
+           </listitem>
+         </itemizedlist>
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>Encoders (struct <structname>drm_encoder</structname>)</title>
+       <para>
+         An encoder takes pixel data from a CRTC and converts it to a format
+       suitable for any attached connectors. On some devices, it may be
+       possible to have a CRTC send data to more than one encoder. In that
+       case, both encoders would receive data from the same scanout buffer,
+       resulting in a "cloned" display configuration across the connectors
+       attached to each encoder.
+       </para>
+       <sect3>
+         <title>Encoder Initialization</title>
+         <para>
+           As for CRTCs, a KMS driver must create, initialize and register at
+           least one struct <structname>drm_encoder</structname> instance. The
+           instance is allocated and zeroed by the driver, possibly as part of a
+           larger structure.
+         </para>
+         <para>
+           Drivers must initialize the struct <structname>drm_encoder</structname>
+           <structfield>possible_crtcs</structfield> and
+           <structfield>possible_clones</structfield> fields before registering the
+           encoder. Both fields are bitmasks of respectively the CRTCs that the
+           encoder can be connected to, and sibling encoders candidate for cloning.
+         </para>
+         <para>
+           After being initialized, the encoder must be registered with a call to
+           <function>drm_encoder_init</function>. The function takes a pointer to
+           the encoder functions and an encoder type. Supported types are
+           <itemizedlist>
+             <listitem>
+               DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A
+               </listitem>
+             <listitem>
+               DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort
+             </listitem>
+             <listitem>
+               DRM_MODE_ENCODER_LVDS for display panels
+             </listitem>
+             <listitem>
+               DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, Component,
+               SCART)
+             </listitem>
+             <listitem>
+               DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
+             </listitem>
+           </itemizedlist>
+         </para>
+         <para>
+           Encoders must be attached to a CRTC to be used. DRM drivers leave
+           encoders unattached at initialization time. Applications (or the fbdev
+           compatibility layer when implemented) are responsible for attaching the
+           encoders they want to use to a CRTC.
+         </para>
+       </sect3>
+       <sect3>
+         <title>Encoder Operations</title>
+         <itemizedlist>
+           <listitem>
+             <synopsis>void (*destroy)(struct drm_encoder *encoder);</synopsis>
+             <para>
+               Called to destroy the encoder when not needed anymore. See
+               <xref linkend="drm-kms-init"/>.
+             </para>
+           </listitem>
+           <listitem>
+             <synopsis>void (*set_property)(struct drm_plane *plane,
+                      struct drm_property *property, uint64_t value);</synopsis>
+             <para>
+               Set the value of the given plane property to
+               <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
+               for more information about properties.
+             </para>
+           </listitem>
+         </itemizedlist>
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>Connectors (struct <structname>drm_connector</structname>)</title>
+       <para>
+         A connector is the final destination for pixel data on a device, and
+       usually connects directly to an external display device like a monitor
+       or laptop panel. A connector can only be attached to one encoder at a
+       time. The connector is also the structure where information about the
+       attached display is kept, so it contains fields for display data, EDID
+       data, DPMS &amp; connection status, and information about modes
+       supported on the attached displays.
+       </para>
+       <sect3>
+         <title>Connector Initialization</title>
+         <para>
+           Finally a KMS driver must create, initialize, register and attach at
+           least one struct <structname>drm_connector</structname> instance. The
+           instance is created as other KMS objects and initialized by setting the
+           following fields.
+         </para>
+         <variablelist>
+           <varlistentry>
+             <term><structfield>interlace_allowed</structfield></term>
+             <listitem><para>
+               Whether the connector can handle interlaced modes.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><structfield>doublescan_allowed</structfield></term>
+             <listitem><para>
+               Whether the connector can handle doublescan.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><structfield>display_info
+             </structfield></term>
+             <listitem><para>
+               Display information is filled from EDID information when a display
+               is detected. For non hot-pluggable displays such as flat panels in
+               embedded systems, the driver should initialize the
+               <structfield>display_info</structfield>.<structfield>width_mm</structfield>
+               and
+               <structfield>display_info</structfield>.<structfield>height_mm</structfield>
+               fields with the physical size of the display.
+             </para></listitem>
+           </varlistentry>
+           <varlistentry>
+             <term id="drm-kms-connector-polled"><structfield>polled</structfield></term>
+             <listitem><para>
+               Connector polling mode, a combination of
+               <variablelist>
+                 <varlistentry>
+                   <term>DRM_CONNECTOR_POLL_HPD</term>
+                   <listitem><para>
+                     The connector generates hotplug events and doesn't need to be
+                     periodically polled. The CONNECT and DISCONNECT flags must not
+                     be set together with the HPD flag.
+                   </para></listitem>
+                 </varlistentry>
+                 <varlistentry>
+                   <term>DRM_CONNECTOR_POLL_CONNECT</term>
+                   <listitem><para>
+                     Periodically poll the connector for connection.
+                   </para></listitem>
+                 </varlistentry>
+                 <varlistentry>
+                   <term>DRM_CONNECTOR_POLL_DISCONNECT</term>
+                   <listitem><para>
+                     Periodically poll the connector for disconnection.
+                   </para></listitem>
+                 </varlistentry>
+               </variablelist>
+               Set to 0 for connectors that don't support connection status
+               discovery.
+             </para></listitem>
+           </varlistentry>
+         </variablelist>
+         <para>
+           The connector is then registered with a call to
+           <function>drm_connector_init</function> with a pointer to the connector
+           functions and a connector type, and exposed through sysfs with a call to
+           <function>drm_connector_register</function>.
+         </para>
+         <para>
+           Supported connector types are
+           <itemizedlist>
+             <listitem>DRM_MODE_CONNECTOR_VGA</listitem>
+             <listitem>DRM_MODE_CONNECTOR_DVII</listitem>
+             <listitem>DRM_MODE_CONNECTOR_DVID</listitem>
+             <listitem>DRM_MODE_CONNECTOR_DVIA</listitem>
+             <listitem>DRM_MODE_CONNECTOR_Composite</listitem>
+             <listitem>DRM_MODE_CONNECTOR_SVIDEO</listitem>
+             <listitem>DRM_MODE_CONNECTOR_LVDS</listitem>
+             <listitem>DRM_MODE_CONNECTOR_Component</listitem>
+             <listitem>DRM_MODE_CONNECTOR_9PinDIN</listitem>
+             <listitem>DRM_MODE_CONNECTOR_DisplayPort</listitem>
+             <listitem>DRM_MODE_CONNECTOR_HDMIA</listitem>
+             <listitem>DRM_MODE_CONNECTOR_HDMIB</listitem>
+             <listitem>DRM_MODE_CONNECTOR_TV</listitem>
+             <listitem>DRM_MODE_CONNECTOR_eDP</listitem>
+             <listitem>DRM_MODE_CONNECTOR_VIRTUAL</listitem>
+           </itemizedlist>
+         </para>
+         <para>
+           Connectors must be attached to an encoder to be used. For devices that
+           map connectors to encoders 1:1, the connector should be attached at
+           initialization time with a call to
+           <function>drm_mode_connector_attach_encoder</function>. The driver must
+           also set the <structname>drm_connector</structname>
+           <structfield>encoder</structfield> field to point to the attached
+           encoder.
+         </para>
+         <para>
+           Finally, drivers must initialize the connectors state change detection
+           with a call to <function>drm_kms_helper_poll_init</function>. If at
+           least one connector is pollable but can't generate hotplug interrupts
+           (indicated by the DRM_CONNECTOR_POLL_CONNECT and
+           DRM_CONNECTOR_POLL_DISCONNECT connector flags), a delayed work will
+           automatically be queued to periodically poll for changes. Connectors
+           that can generate hotplug interrupts must be marked with the
+           DRM_CONNECTOR_POLL_HPD flag instead, and their interrupt handler must
+           call <function>drm_helper_hpd_irq_event</function>. The function will
+           queue a delayed work to check the state of all connectors, but no
+           periodic polling will be done.
+         </para>
+       </sect3>
+       <sect3>
+         <title>Connector Operations</title>
+         <note><para>
+           Unless otherwise state, all operations are mandatory.
+         </para></note>
+         <sect4>
+           <title>DPMS</title>
+           <synopsis>void (*dpms)(struct drm_connector *connector, int mode);</synopsis>
+           <para>
+             The DPMS operation sets the power state of a connector. The mode
+             argument is one of
+             <itemizedlist>
+               <listitem><para>DRM_MODE_DPMS_ON</para></listitem>
+               <listitem><para>DRM_MODE_DPMS_STANDBY</para></listitem>
+               <listitem><para>DRM_MODE_DPMS_SUSPEND</para></listitem>
+               <listitem><para>DRM_MODE_DPMS_OFF</para></listitem>
+             </itemizedlist>
+           </para>
+           <para>
+             In all but DPMS_ON mode the encoder to which the connector is attached
+             should put the display in low-power mode by driving its signals
+             appropriately. If more than one connector is attached to the encoder
+             care should be taken not to change the power state of other displays as
+             a side effect. Low-power mode should be propagated to the encoders and
+             CRTCs when all related connectors are put in low-power mode.
+           </para>
+         </sect4>
+         <sect4>
+           <title>Modes</title>
+           <synopsis>int (*fill_modes)(struct drm_connector *connector, uint32_t max_width,
+                       uint32_t max_height);</synopsis>
+           <para>
+             Fill the mode list with all supported modes for the connector. If the
+             <parameter>max_width</parameter> and <parameter>max_height</parameter>
+             arguments are non-zero, the implementation must ignore all modes wider
+             than <parameter>max_width</parameter> or higher than
+             <parameter>max_height</parameter>.
+           </para>
+           <para>
+             The connector must also fill in this operation its
+             <structfield>display_info</structfield>
+             <structfield>width_mm</structfield> and
+             <structfield>height_mm</structfield> fields with the connected display
+             physical size in millimeters. The fields should be set to 0 if the value
+             isn't known or is not applicable (for instance for projector devices).
+           </para>
+         </sect4>
+         <sect4>
+           <title>Connection Status</title>
+           <para>
+             The connection status is updated through polling or hotplug events when
+             supported (see <xref linkend="drm-kms-connector-polled"/>). The status
+             value is reported to userspace through ioctls and must not be used
+             inside the driver, as it only gets initialized by a call to
+             <function>drm_mode_getconnector</function> from userspace.
+           </para>
+           <synopsis>enum drm_connector_status (*detect)(struct drm_connector *connector,
+                                         bool force);</synopsis>
+           <para>
+             Check to see if anything is attached to the connector. The
+             <parameter>force</parameter> parameter is set to false whilst polling or
+             to true when checking the connector due to user request.
+             <parameter>force</parameter> can be used by the driver to avoid
+             expensive, destructive operations during automated probing.
+           </para>
+           <para>
+             Return connector_status_connected if something is connected to the
+             connector, connector_status_disconnected if nothing is connected and
+             connector_status_unknown if the connection state isn't known.
+           </para>
+           <para>
+             Drivers should only return connector_status_connected if the connection
+             status has really been probed as connected. Connectors that can't detect
+             the connection status, or failed connection status probes, should return
+             connector_status_unknown.
+           </para>
+         </sect4>
+         <sect4>
+           <title>Miscellaneous</title>
+           <itemizedlist>
+             <listitem>
+               <synopsis>void (*set_property)(struct drm_connector *connector,
+                      struct drm_property *property, uint64_t value);</synopsis>
+               <para>
+                 Set the value of the given connector property to
+                 <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
+                 for more information about properties.
+               </para>
+             </listitem>
+             <listitem>
+               <synopsis>void (*destroy)(struct drm_connector *connector);</synopsis>
+               <para>
+                 Destroy the connector when not needed anymore. See
+                 <xref linkend="drm-kms-init"/>.
+               </para>
+             </listitem>
+           </itemizedlist>
+         </sect4>
+       </sect3>
+     </sect2>
+     <sect2>
+       <title>Cleanup</title>
+       <para>
+         The DRM core manages its objects' lifetime. When an object is not needed
+       anymore the core calls its destroy function, which must clean up and
+       free every resource allocated for the object. Every
+       <function>drm_*_init</function> call must be matched with a
+       corresponding <function>drm_*_cleanup</function> call to cleanup CRTCs
+       (<function>drm_crtc_cleanup</function>), planes
+       (<function>drm_plane_cleanup</function>), encoders
+       (<function>drm_encoder_cleanup</function>) and connectors
+       (<function>drm_connector_cleanup</function>). Furthermore, connectors
+       that have been added to sysfs must be removed by a call to
+       <function>drm_connector_unregister</function> before calling
+       <function>drm_connector_cleanup</function>.
+       </para>
+       <para>
+         Connectors state change detection must be cleanup up with a call to
+       <function>drm_kms_helper_poll_fini</function>.
+       </para>
+     </sect2>
+     <sect2>
+       <title>Output discovery and initialization example</title>
+       <programlisting><![CDATA[
+ void intel_crt_init(struct drm_device *dev)
+ {
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output)
+               return;
+       connector = &intel_output->base;
+       drm_connector_init(dev, &intel_output->base,
+                          &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+       drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs,
+                        DRM_MODE_ENCODER_DAC);
+       drm_mode_connector_attach_encoder(&intel_output->base,
+                                         &intel_output->enc);
+       /* Set up the DDC bus. */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
+       if (!intel_output->ddc_bus) {
+               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
+                          "failed.\n");
+               return;
+       }
+       intel_output->type = INTEL_OUTPUT_ANALOG;
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+       drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs);
+       drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
+       drm_connector_register(connector);
+ }]]></programlisting>
+       <para>
+         In the example above (taken from the i915 driver), a CRTC, connector and
+         encoder combination is created. A device-specific i2c bus is also
+         created for fetching EDID data and performing monitor detection. Once
+         the process is complete, the new connector is registered with sysfs to
+         make its properties available to applications.
+       </para>
+     </sect2>
+     <sect2>
+       <title>KMS API Functions</title>
+ !Edrivers/gpu/drm/drm_crtc.c
+     </sect2>
+     <sect2>
+       <title>KMS Data Structures</title>
+ !Iinclude/drm/drm_crtc.h
+     </sect2>
+     <sect2>
+       <title>KMS Locking</title>
+ !Pdrivers/gpu/drm/drm_modeset_lock.c kms locking
+ !Iinclude/drm/drm_modeset_lock.h
+ !Edrivers/gpu/drm/drm_modeset_lock.c
+     </sect2>
+   </sect1>
+   <!-- Internals: kms helper functions -->
+   <sect1>
+     <title>Mode Setting Helper Functions</title>
+     <para>
+       The plane, CRTC, encoder and connector functions provided by the drivers
+       implement the DRM API. They're called by the DRM core and ioctl handlers
+       to handle device state changes and configuration request. As implementing
+       those functions often requires logic not specific to drivers, mid-layer
+       helper functions are available to avoid duplicating boilerplate code.
+     </para>
+     <para>
+       The DRM core contains one mid-layer implementation. The mid-layer provides
+       implementations of several plane, CRTC, encoder and connector functions
+       (called from the top of the mid-layer) that pre-process requests and call
+       lower-level functions provided by the driver (at the bottom of the
+       mid-layer). For instance, the
+       <function>drm_crtc_helper_set_config</function> function can be used to
+       fill the struct <structname>drm_crtc_funcs</structname>
+       <structfield>set_config</structfield> field. When called, it will split
+       the <methodname>set_config</methodname> operation in smaller, simpler
+       operations and call the driver to handle them.
+     </para>
+     <para>
+       To use the mid-layer, drivers call <function>drm_crtc_helper_add</function>,
+       <function>drm_encoder_helper_add</function> and
+       <function>drm_connector_helper_add</function> functions to install their
+       mid-layer bottom operations handlers, and fill the
+       <structname>drm_crtc_funcs</structname>,
+       <structname>drm_encoder_funcs</structname> and
+       <structname>drm_connector_funcs</structname> structures with pointers to
+       the mid-layer top API functions. Installing the mid-layer bottom operation
+       handlers is best done right after registering the corresponding KMS object.
+     </para>
+     <para>
+       The mid-layer is not split between CRTC, encoder and connector operations.
+       To use it, a driver must provide bottom functions for all of the three KMS
+       entities.
+     </para>
+     <sect2>
+       <title>Helper Functions</title>
+       <itemizedlist>
+         <listitem>
+           <synopsis>int drm_crtc_helper_set_config(struct drm_mode_set *set);</synopsis>
+           <para>
+             The <function>drm_crtc_helper_set_config</function> helper function
+             is a CRTC <methodname>set_config</methodname> implementation. It
+             first tries to locate the best encoder for each connector by calling
+             the connector <methodname>best_encoder</methodname> helper
+             operation.
+           </para>
+           <para>
+             After locating the appropriate encoders, the helper function will
+             call the <methodname>mode_fixup</methodname> encoder and CRTC helper
+             operations to adjust the requested mode, or reject it completely in
+             which case an error will be returned to the application. If the new
+             configuration after mode adjustment is identical to the current
+             configuration the helper function will return without performing any
+             other operation.
+           </para>
+           <para>
+             If the adjusted mode is identical to the current mode but changes to
+             the frame buffer need to be applied, the
+             <function>drm_crtc_helper_set_config</function> function will call
+             the CRTC <methodname>mode_set_base</methodname> helper operation. If
+             the adjusted mode differs from the current mode, or if the
+             <methodname>mode_set_base</methodname> helper operation is not
+             provided, the helper function performs a full mode set sequence by
+             calling the <methodname>prepare</methodname>,
+             <methodname>mode_set</methodname> and
+             <methodname>commit</methodname> CRTC and encoder helper operations,
+             in that order.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>void drm_helper_connector_dpms(struct drm_connector *connector, int mode);</synopsis>
+           <para>
+             The <function>drm_helper_connector_dpms</function> helper function
+             is a connector <methodname>dpms</methodname> implementation that
+             tracks power state of connectors. To use the function, drivers must
+             provide <methodname>dpms</methodname> helper operations for CRTCs
+             and encoders to apply the DPMS state to the device.
+           </para>
+           <para>
+             The mid-layer doesn't track the power state of CRTCs and encoders.
+             The <methodname>dpms</methodname> helper operations can thus be
+             called with a mode identical to the currently active mode.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
+                                             uint32_t maxX, uint32_t maxY);</synopsis>
+           <para>
+             The <function>drm_helper_probe_single_connector_modes</function> helper
+             function is a connector <methodname>fill_modes</methodname>
+             implementation that updates the connection status for the connector
+             and then retrieves a list of modes by calling the connector
+             <methodname>get_modes</methodname> helper operation.
+           </para>
+          <para>
+             If the helper operation returns no mode, and if the connector status
+             is connector_status_connected, standard VESA DMT modes up to
+             1024x768 are automatically added to the modes list by a call to
+             <function>drm_add_modes_noedid</function>.
+           </para>
+           <para>
+             The function then filters out modes larger than
+             <parameter>max_width</parameter> and <parameter>max_height</parameter>
+             if specified. It finally calls the optional connector
+             <methodname>mode_valid</methodname> helper operation for each mode in
+             the probed list to check whether the mode is valid for the connector.
+           </para>
+         </listitem>
+       </itemizedlist>
+     </sect2>
+     <sect2>
+       <title>CRTC Helper Operations</title>
+       <itemizedlist>
+         <listitem id="drm-helper-crtc-mode-fixup">
+           <synopsis>bool (*mode_fixup)(struct drm_crtc *crtc,
+                        const struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode);</synopsis>
+           <para>
+             Let CRTCs adjust the requested mode or reject it completely. This
+             operation returns true if the mode is accepted (possibly after being
+             adjusted) or false if it is rejected.
+           </para>
+           <para>
+             The <methodname>mode_fixup</methodname> operation should reject the
+             mode if it can't reasonably use it. The definition of "reasonable"
+             is currently fuzzy in this context. One possible behaviour would be
+             to set the adjusted mode to the panel timings when a fixed-mode
+             panel is used with hardware capable of scaling. Another behaviour
+             would be to accept any input mode and adjust it to the closest mode
+             supported by the hardware (FIXME: This needs to be clarified).
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
+                      struct drm_framebuffer *old_fb)</synopsis>
+           <para>
+             Move the CRTC on the current frame buffer (stored in
+             <literal>crtc-&gt;fb</literal>) to position (x,y). Any of the frame
+             buffer, x position or y position may have been modified.
+           </para>
+           <para>
+             This helper operation is optional. If not provided, the
+             <function>drm_crtc_helper_set_config</function> function will fall
+             back to the <methodname>mode_set</methodname> helper operation.
+           </para>
+           <note><para>
+             FIXME: Why are x and y passed as arguments, as they can be accessed
+             through <literal>crtc-&gt;x</literal> and
+             <literal>crtc-&gt;y</literal>?
+           </para></note>
+         </listitem>
+         <listitem>
+           <synopsis>void (*prepare)(struct drm_crtc *crtc);</synopsis>
+           <para>
+             Prepare the CRTC for mode setting. This operation is called after
+             validating the requested mode. Drivers use it to perform
+             device-specific operations required before setting the new mode.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                 struct drm_display_mode *adjusted_mode, int x, int y,
+                 struct drm_framebuffer *old_fb);</synopsis>
+           <para>
+             Set a new mode, position and frame buffer. Depending on the device
+             requirements, the mode can be stored internally by the driver and
+             applied in the <methodname>commit</methodname> operation, or
+             programmed to the hardware immediately.
+           </para>
+           <para>
+             The <methodname>mode_set</methodname> operation returns 0 on success
+           or a negative error code if an error occurs.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>void (*commit)(struct drm_crtc *crtc);</synopsis>
+           <para>
+             Commit a mode. This operation is called after setting the new mode.
+             Upon return the device must use the new mode and be fully
+             operational.
+           </para>
+         </listitem>
+       </itemizedlist>
+     </sect2>
+     <sect2>
+       <title>Encoder Helper Operations</title>
+       <itemizedlist>
+         <listitem>
+           <synopsis>bool (*mode_fixup)(struct drm_encoder *encoder,
+                        const struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode);</synopsis>
+           <para>
+             Let encoders adjust the requested mode or reject it completely. This
+             operation returns true if the mode is accepted (possibly after being
+             adjusted) or false if it is rejected. See the
+             <link linkend="drm-helper-crtc-mode-fixup">mode_fixup CRTC helper
+             operation</link> for an explanation of the allowed adjustments.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>void (*prepare)(struct drm_encoder *encoder);</synopsis>
+           <para>
+             Prepare the encoder for mode setting. This operation is called after
+             validating the requested mode. Drivers use it to perform
+             device-specific operations required before setting the new mode.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>void (*mode_set)(struct drm_encoder *encoder,
+                  struct drm_display_mode *mode,
+                  struct drm_display_mode *adjusted_mode);</synopsis>
+           <para>
+             Set a new mode. Depending on the device requirements, the mode can
+             be stored internally by the driver and applied in the
+             <methodname>commit</methodname> operation, or programmed to the
+             hardware immediately.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>void (*commit)(struct drm_encoder *encoder);</synopsis>
+           <para>
+             Commit a mode. This operation is called after setting the new mode.
+             Upon return the device must use the new mode and be fully
+             operational.
+           </para>
+         </listitem>
+       </itemizedlist>
+     </sect2>
+     <sect2>
+       <title>Connector Helper Operations</title>
+       <itemizedlist>
+         <listitem>
+           <synopsis>struct drm_encoder *(*best_encoder)(struct drm_connector *connector);</synopsis>
+           <para>
+             Return a pointer to the best encoder for the connecter. Device that
+             map connectors to encoders 1:1 simply return the pointer to the
+             associated encoder. This operation is mandatory.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int (*get_modes)(struct drm_connector *connector);</synopsis>
+           <para>
+             Fill the connector's <structfield>probed_modes</structfield> list
+             by parsing EDID data with <function>drm_add_edid_modes</function>,
+             adding standard VESA DMT modes with <function>drm_add_modes_noedid</function>,
+             or calling <function>drm_mode_probed_add</function> directly for every
+             supported mode and return the number of modes it has detected. This
+             operation is mandatory.
+           </para>
+           <para>
+             Note that the caller function will automatically add standard VESA
+             DMT modes up to 1024x768 if the <methodname>get_modes</methodname>
+             helper operation returns no mode and if the connector status is
+             connector_status_connected. There is no need to call
+             <function>drm_add_edid_modes</function> manually in that case.
+           </para>
+           <para>
+             When adding modes manually the driver creates each mode with a call to
+             <function>drm_mode_create</function> and must fill the following fields.
+             <itemizedlist>
+               <listitem>
+                 <synopsis>__u32 type;</synopsis>
+                 <para>
+                   Mode type bitmask, a combination of
+                   <variablelist>
+                     <varlistentry>
+                       <term>DRM_MODE_TYPE_BUILTIN</term>
+                       <listitem><para>not used?</para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_TYPE_CLOCK_C</term>
+                       <listitem><para>not used?</para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_TYPE_CRTC_C</term>
+                       <listitem><para>not used?</para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>
+         DRM_MODE_TYPE_PREFERRED - The preferred mode for the connector
+                       </term>
+                       <listitem>
+                         <para>not used?</para>
+                       </listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_TYPE_DEFAULT</term>
+                       <listitem><para>not used?</para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_TYPE_USERDEF</term>
+                       <listitem><para>not used?</para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_TYPE_DRIVER</term>
+                       <listitem>
+                         <para>
+                           The mode has been created by the driver (as opposed to
+                           to user-created modes).
+                         </para>
+                       </listitem>
+                     </varlistentry>
+                   </variablelist>
+                   Drivers must set the DRM_MODE_TYPE_DRIVER bit for all modes they
+                   create, and set the DRM_MODE_TYPE_PREFERRED bit for the preferred
+                   mode.
+                 </para>
+               </listitem>
+               <listitem>
+                 <synopsis>__u32 clock;</synopsis>
+                 <para>Pixel clock frequency in kHz unit</para>
+               </listitem>
+               <listitem>
+                 <synopsis>__u16 hdisplay, hsync_start, hsync_end, htotal;
+     __u16 vdisplay, vsync_start, vsync_end, vtotal;</synopsis>
+                 <para>Horizontal and vertical timing information</para>
+                 <screen><![CDATA[
+              Active                 Front           Sync           Back
+              Region                 Porch                          Porch
+     <-----------------------><----------------><-------------><-------------->
+       //////////////////////|
+      ////////////////////// |
+     //////////////////////  |..................               ................
+                                                _______________
+     <----- [hv]display ----->
+     <------------- [hv]sync_start ------------>
+     <--------------------- [hv]sync_end --------------------->
+     <-------------------------------- [hv]total ----------------------------->
+ ]]></screen>
+               </listitem>
+               <listitem>
+                 <synopsis>__u16 hskew;
+     __u16 vscan;</synopsis>
+                 <para>Unknown</para>
+               </listitem>
+               <listitem>
+                 <synopsis>__u32 flags;</synopsis>
+                 <para>
+                   Mode flags, a combination of
+                   <variablelist>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_PHSYNC</term>
+                       <listitem><para>
+                         Horizontal sync is active high
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_NHSYNC</term>
+                       <listitem><para>
+                         Horizontal sync is active low
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_PVSYNC</term>
+                       <listitem><para>
+                         Vertical sync is active high
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_NVSYNC</term>
+                       <listitem><para>
+                         Vertical sync is active low
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_INTERLACE</term>
+                       <listitem><para>
+                         Mode is interlaced
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_DBLSCAN</term>
+                       <listitem><para>
+                         Mode uses doublescan
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_CSYNC</term>
+                       <listitem><para>
+                         Mode uses composite sync
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_PCSYNC</term>
+                       <listitem><para>
+                         Composite sync is active high
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_NCSYNC</term>
+                       <listitem><para>
+                         Composite sync is active low
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_HSKEW</term>
+                       <listitem><para>
+                         hskew provided (not used?)
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_BCAST</term>
+                       <listitem><para>
+                         not used?
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_PIXMUX</term>
+                       <listitem><para>
+                         not used?
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_DBLCLK</term>
+                       <listitem><para>
+                         not used?
+                       </para></listitem>
+                     </varlistentry>
+                     <varlistentry>
+                       <term>DRM_MODE_FLAG_CLKDIV2</term>
+                       <listitem><para>
+                         ?
+                       </para></listitem>
+                     </varlistentry>
+                   </variablelist>
+                 </para>
+                 <para>
+                   Note that modes marked with the INTERLACE or DBLSCAN flags will be
+                   filtered out by
+                   <function>drm_helper_probe_single_connector_modes</function> if
+                   the connector's <structfield>interlace_allowed</structfield> or
+                   <structfield>doublescan_allowed</structfield> field is set to 0.
+                 </para>
+               </listitem>
+               <listitem>
+                 <synopsis>char name[DRM_DISPLAY_MODE_LEN];</synopsis>
+                 <para>
+                   Mode name. The driver must call
+                   <function>drm_mode_set_name</function> to fill the mode name from
+                   <structfield>hdisplay</structfield>,
+                   <structfield>vdisplay</structfield> and interlace flag after
+                   filling the corresponding fields.
+                 </para>
+               </listitem>
+             </itemizedlist>
+           </para>
+           <para>
+             The <structfield>vrefresh</structfield> value is computed by
+             <function>drm_helper_probe_single_connector_modes</function>.
+           </para>
+           <para>
+             When parsing EDID data, <function>drm_add_edid_modes</function> fills the
+             connector <structfield>display_info</structfield>
+             <structfield>width_mm</structfield> and
+             <structfield>height_mm</structfield> fields. When creating modes
+             manually the <methodname>get_modes</methodname> helper operation must
+             set the <structfield>display_info</structfield>
+             <structfield>width_mm</structfield> and
+             <structfield>height_mm</structfield> fields if they haven't been set
+             already (for instance at initialization time when a fixed-size panel is
+             attached to the connector). The mode <structfield>width_mm</structfield>
+             and <structfield>height_mm</structfield> fields are only used internally
+             during EDID parsing and should not be set when creating modes manually.
+           </para>
+         </listitem>
+         <listitem>
+           <synopsis>int (*mode_valid)(struct drm_connector *connector,
+                 struct drm_display_mode *mode);</synopsis>
+           <para>
+             Verify whether a mode is valid for the connector. Return MODE_OK for
+             supported modes and one of the enum drm_mode_status values (MODE_*)
+             for unsupported modes. This operation is optional.
+           </para>
+           <para>
+             As the mode rejection reason is currently not used beside for
+             immediately removing the unsupported mode, an implementation can
+             return MODE_BAD regardless of the exact reason why the mode is not
+             valid.
+           </para>
+           <note><para>
+             Note that the <methodname>mode_valid</methodname> helper operation is
+             only called for modes detected by the device, and
+             <emphasis>not</emphasis> for modes set by the user through the CRTC
+             <methodname>set_config</methodname> operation.
+           </para></note>
+         </listitem>
+       </itemizedlist>
+     </sect2>
+     <sect2>
+       <title>Atomic Modeset Helper Functions Reference</title>
+       <sect3>
+       <title>Overview</title>
+ !Pdrivers/gpu/drm/drm_atomic_helper.c overview
+       </sect3>
+       <sect3>
+       <title>Implementing Asynchronous Atomic Commit</title>
+ !Pdrivers/gpu/drm/drm_atomic_helper.c implementing async commit
+       </sect3>
+       <sect3>
+       <title>Atomic State Reset and Initialization</title>
+ !Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
+       </sect3>
+ !Iinclude/drm/drm_atomic_helper.h
+ !Edrivers/gpu/drm/drm_atomic_helper.c
+     </sect2>
+     <sect2>
+       <title>Modeset Helper Functions Reference</title>
+ !Iinclude/drm/drm_crtc_helper.h
+ !Edrivers/gpu/drm/drm_crtc_helper.c
+ !Pdrivers/gpu/drm/drm_crtc_helper.c overview
+     </sect2>
+     <sect2>
+       <title>Output Probing Helper Functions Reference</title>
+ !Pdrivers/gpu/drm/drm_probe_helper.c output probing helper overview
+ !Edrivers/gpu/drm/drm_probe_helper.c
+     </sect2>
+     <sect2>
+       <title>fbdev Helper Functions Reference</title>
+ !Pdrivers/gpu/drm/drm_fb_helper.c fbdev helpers
+ !Edrivers/gpu/drm/drm_fb_helper.c
+ !Iinclude/drm/drm_fb_helper.h
+     </sect2>
+     <sect2>
+       <title>Display Port Helper Functions Reference</title>
+ !Pdrivers/gpu/drm/drm_dp_helper.c dp helpers
+ !Iinclude/drm/drm_dp_helper.h
+ !Edrivers/gpu/drm/drm_dp_helper.c
+     </sect2>
+     <sect2>
+       <title>Display Port MST Helper Functions Reference</title>
+ !Pdrivers/gpu/drm/drm_dp_mst_topology.c dp mst helper
+ !Iinclude/drm/drm_dp_mst_helper.h
+ !Edrivers/gpu/drm/drm_dp_mst_topology.c
+     </sect2>
+     <sect2>
+       <title>MIPI DSI Helper Functions Reference</title>
+ !Pdrivers/gpu/drm/drm_mipi_dsi.c dsi helpers
+ !Iinclude/drm/drm_mipi_dsi.h
+ !Edrivers/gpu/drm/drm_mipi_dsi.c
+     </sect2>
+     <sect2>
+       <title>EDID Helper Functions Reference</title>
+ !Edrivers/gpu/drm/drm_edid.c
+     </sect2>
+     <sect2>
+       <title>Rectangle Utilities Reference</title>
+ !Pinclude/drm/drm_rect.h rect utils
+ !Iinclude/drm/drm_rect.h
+ !Edrivers/gpu/drm/drm_rect.c
+     </sect2>
+     <sect2>
+       <title>Flip-work Helper Reference</title>
+ !Pinclude/drm/drm_flip_work.h flip utils
+ !Iinclude/drm/drm_flip_work.h
+ !Edrivers/gpu/drm/drm_flip_work.c
+     </sect2>
+     <sect2>
+       <title>HDMI Infoframes Helper Reference</title>
+       <para>
+       Strictly speaking this is not a DRM helper library but generally useable
+       by any driver interfacing with HDMI outputs like v4l or alsa drivers.
+       But it nicely fits into the overall topic of mode setting helper
+       libraries and hence is also included here.
+       </para>
+ !Iinclude/linux/hdmi.h
+ !Edrivers/video/hdmi.c
+     </sect2>
+     <sect2>
+       <title id="drm-kms-planehelpers">Plane Helper Reference</title>
+ !Edrivers/gpu/drm/drm_plane_helper.c
+ !Pdrivers/gpu/drm/drm_plane_helper.c overview
+     </sect2>
+     <sect2>
+         <title>Tile group</title>
+ !Pdrivers/gpu/drm/drm_crtc.c Tile group
+     </sect2>
+     <sect2>
+       <title>Bridges</title>
+       <sect3>
+        <title>Overview</title>
+ !Pdrivers/gpu/drm/drm_bridge.c overview
+       </sect3>
+       <sect3>
+        <title>Default bridge callback sequence</title>
+ !Pdrivers/gpu/drm/drm_bridge.c bridge callbacks
+       </sect3>
+ !Edrivers/gpu/drm/drm_bridge.c
+     </sect2>
+   </sect1>
+   <!-- Internals: kms properties -->
+   <sect1 id="drm-kms-properties">
+     <title>KMS Properties</title>
+     <para>
+       Drivers may need to expose additional parameters to applications than
+       those described in the previous sections. KMS supports attaching
+       properties to CRTCs, connectors and planes and offers a userspace API to
+       list, get and set the property values.
+     </para>
+     <para>
+       Properties are identified by a name that uniquely defines the property
+       purpose, and store an associated value. For all property types except blob
+       properties the value is a 64-bit unsigned integer.
+     </para>
+     <para>
+       KMS differentiates between properties and property instances. Drivers
+       first create properties and then create and associate individual instances
+       of those properties to objects. A property can be instantiated multiple
+       times and associated with different objects. Values are stored in property
+       instances, and all other property information are stored in the property
+       and shared between all instances of the property.
+     </para>
+     <para>
+       Every property is created with a type that influences how the KMS core
+       handles the property. Supported property types are
+       <variablelist>
+         <varlistentry>
+           <term>DRM_MODE_PROP_RANGE</term>
+           <listitem><para>Range properties report their minimum and maximum
+             admissible values. The KMS core verifies that values set by
+             application fit in that range.</para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>DRM_MODE_PROP_ENUM</term>
+           <listitem><para>Enumerated properties take a numerical value that
+             ranges from 0 to the number of enumerated values defined by the
+             property minus one, and associate a free-formed string name to each
+             value. Applications can retrieve the list of defined value-name pairs
+             and use the numerical value to get and set property instance values.
+             </para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>DRM_MODE_PROP_BITMASK</term>
+           <listitem><para>Bitmask properties are enumeration properties that
+             additionally restrict all enumerated values to the 0..63 range.
+             Bitmask property instance values combine one or more of the
+             enumerated bits defined by the property.</para></listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>DRM_MODE_PROP_BLOB</term>
+           <listitem><para>Blob properties store a binary blob without any format
+             restriction. The binary blobs are created as KMS standalone objects,
+             and blob property instance values store the ID of their associated
+             blob object.</para>
+           <para>Blob properties are only used for the connector EDID property
+           and cannot be created by drivers.</para></listitem>
+         </varlistentry>
+       </variablelist>
+     </para>
+     <para>
+       To create a property drivers call one of the following functions depending
+       on the property type. All property creation functions take property flags
+       and name, as well as type-specific arguments.
+       <itemizedlist>
+         <listitem>
+           <synopsis>struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+                                                const char *name,
+                                                uint64_t min, uint64_t max);</synopsis>
+           <para>Create a range property with the given minimum and maximum
+             values.</para>
+         </listitem>
+         <listitem>
+           <synopsis>struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+                                               const char *name,
+                                               const struct drm_prop_enum_list *props,
+                                               int num_values);</synopsis>
+           <para>Create an enumerated property. The <parameter>props</parameter>
+             argument points to an array of <parameter>num_values</parameter>
+             value-name pairs.</para>
+         </listitem>
+         <listitem>
+           <synopsis>struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
+                                                  int flags, const char *name,
+                                                  const struct drm_prop_enum_list *props,
+                                                  int num_values);</synopsis>
+           <para>Create a bitmask property. The <parameter>props</parameter>
+             argument points to an array of <parameter>num_values</parameter>
+             value-name pairs.</para>
+         </listitem>
+       </itemizedlist>
+     </para>
+     <para>
+       Properties can additionally be created as immutable, in which case they
+       will be read-only for applications but can be modified by the driver. To
+       create an immutable property drivers must set the DRM_MODE_PROP_IMMUTABLE
+       flag at property creation time.
+     </para>
+     <para>
+       When no array of value-name pairs is readily available at property
+       creation time for enumerated or range properties, drivers can create
+       the property using the <function>drm_property_create</function> function
+       and manually add enumeration value-name pairs by calling the
+       <function>drm_property_add_enum</function> function. Care must be taken to
+       properly specify the property type through the <parameter>flags</parameter>
+       argument.
+     </para>
+     <para>
+       After creating properties drivers can attach property instances to CRTC,
+       connector and plane objects by calling the
+       <function>drm_object_attach_property</function>. The function takes a
+       pointer to the target object, a pointer to the previously created property
+       and an initial instance value.
+     </para>
+     <sect2>
+       <title>Existing KMS Properties</title>
+       <para>
+       The following table gives description of drm properties exposed by various
+       modules/drivers.
+       </para>
+       <table border="1" cellpadding="0" cellspacing="0">
+       <tbody>
+       <tr style="font-weight: bold;">
+       <td valign="top" >Owner Module/Drivers</td>
+       <td valign="top" >Group</td>
+       <td valign="top" >Property Name</td>
+       <td valign="top" >Type</td>
+       <td valign="top" >Property Values</td>
+       <td valign="top" >Object attached</td>
+       <td valign="top" >Description/Restrictions</td>
+       </tr>
+       <tr>
+       <td rowspan="37" valign="top" >DRM</td>
+       <td valign="top" >Generic</td>
+       <td valign="top" >“rotation”</td>
+       <td valign="top" >BITMASK</td>
+       <td valign="top" >{ 0, "rotate-0" },
+       { 1, "rotate-90" },
+       { 2, "rotate-180" },
+       { 3, "rotate-270" },
+       { 4, "reflect-x" },
+       { 5, "reflect-y" }</td>
+       <td valign="top" >CRTC, Plane</td>
+       <td valign="top" >rotate-(degrees) rotates the image by the specified amount in degrees
+       in counter clockwise direction. reflect-x and reflect-y reflects the
+       image along the specified axis prior to rotation</td>
+       </tr>
+       <tr>
+       <td rowspan="5" valign="top" >Connector</td>
+       <td valign="top" >“EDID”</td>
+       <td valign="top" >BLOB | IMMUTABLE</td>
+       <td valign="top" >0</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >Contains id of edid blob ptr object.</td>
+       </tr>
+       <tr>
+       <td valign="top" >“DPMS”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ “On”, “Standby”, “Suspend”, “Off” }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >Contains DPMS operation mode value.</td>
+       </tr>
+       <tr>
+       <td valign="top" >“PATH”</td>
+       <td valign="top" >BLOB | IMMUTABLE</td>
+       <td valign="top" >0</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >Contains topology path to a connector.</td>
+       </tr>
+       <tr>
+       <td valign="top" >“TILE”</td>
+       <td valign="top" >BLOB | IMMUTABLE</td>
+       <td valign="top" >0</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >Contains tiling information for a connector.</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_ID”</td>
+       <td valign="top" >OBJECT</td>
+       <td valign="top" >DRM_MODE_OBJECT_CRTC</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >CRTC that connector is attached to (atomic)</td>
+       </tr>
+       <tr>
+       <td rowspan="11" valign="top" >Plane</td>
+       <td valign="top" >“type”</td>
+       <td valign="top" >ENUM | IMMUTABLE</td>
+       <td valign="top" >{ "Overlay", "Primary", "Cursor" }</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Plane type</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_X”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source x coordinate in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_Y”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source y coordinate in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_W”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source width in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_H”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source height in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_X”</td>
+       <td valign="top" >SIGNED_RANGE</td>
+       <td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) x coordinate (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_Y”</td>
+       <td valign="top" >SIGNED_RANGE</td>
+       <td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) y coordinate (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_W”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) width (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_H”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) height (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“FB_ID”</td>
+       <td valign="top" >OBJECT</td>
+       <td valign="top" >DRM_MODE_OBJECT_FB</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout framebuffer (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_ID”</td>
+       <td valign="top" >OBJECT</td>
+       <td valign="top" >DRM_MODE_OBJECT_CRTC</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >CRTC that plane is attached to (atomic)</td>
+       </tr>
+       <tr>
+       <td rowspan="2" valign="top" >DVI-I</td>
+       <td valign="top" >“subconnector”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ “Unknown”, “DVI-D”, “DVI-A” }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“select subconnector”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ “Automatic”, “DVI-D”, “DVI-A” }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="13" valign="top" >TV</td>
+       <td valign="top" >“subconnector”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "Unknown", "Composite", "SVIDEO", "Component", "SCART" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“select subconnector”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "Automatic", "Composite", "SVIDEO", "Component", "SCART" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "NTSC_M", "NTSC_J", "NTSC_443", "PAL_B" } etc.</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“left margin”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“right margin”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“top margin”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“bottom margin”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“brightness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“contrast”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker reduction”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“overscan”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“saturation”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“hue”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="2" valign="top" >Virtual GPU</td>
+       <td valign="top" >“suggested X”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffffff</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >property to suggest an X offset for a connector</td>
+       </tr>
+       <tr>
+       <td valign="top" >“suggested Y”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffffff</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >property to suggest an Y offset for a connector</td>
+       </tr>
+       <tr>
+       <td rowspan="3" valign="top" >Optional</td>
+       <td valign="top" >“scaling mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "None", "Full", "Center", "Full aspect" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"aspect ratio"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "None", "4:3", "16:9" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >DRM property to set aspect ratio from user space app.
+               This enum is made generic to allow addition of custom aspect
+               ratios.</td>
+       </tr>
+       <tr>
+       <td valign="top" >“dirty”</td>
+       <td valign="top" >ENUM | IMMUTABLE</td>
+       <td valign="top" >{ "Off", "On", "Annotate" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="20" valign="top" >i915</td>
+       <td rowspan="2" valign="top" >Generic</td>
+       <td valign="top" >"Broadcast RGB"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "Automatic", "Full", "Limited 16:235" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“audio”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "force-dvi", "off", "auto", "on" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="17" valign="top" >SDVO-TV</td>
+       <td valign="top" >“mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "NTSC_M", "NTSC_J", "NTSC_443", "PAL_B" } etc.</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"left_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"right_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"top_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"bottom_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“hpos”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“vpos”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“contrast”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“saturation”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“hue”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“sharpness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker_filter”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker_filter_adaptive”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker_filter_2d”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“tv_chroma_filter”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“tv_luma_filter”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“dot_crawl”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >SDVO-TV/LVDS</td>
+       <td valign="top" >“brightness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="2" valign="top" >CDV gma-500</td>
+       <td rowspan="2" valign="top" >Generic</td>
+       <td valign="top" >"Broadcast RGB"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ “Full”, “Limited 16:235” }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"Broadcast RGB"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ “off”, “auto”, “on” }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="19" valign="top" >Poulsbo</td>
+       <td rowspan="1" valign="top" >Generic</td>
+       <td valign="top" >“backlight”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=100</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="17" valign="top" >SDVO-TV</td>
+       <td valign="top" >“mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "NTSC_M", "NTSC_J", "NTSC_443", "PAL_B" } etc.</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"left_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"right_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"top_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"bottom_margin"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“hpos”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“vpos”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“contrast”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“saturation”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“hue”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“sharpness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker_filter”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker_filter_adaptive”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“flicker_filter_2d”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“tv_chroma_filter”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“tv_luma_filter”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“dot_crawl”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >SDVO-TV/LVDS</td>
+       <td valign="top" >“brightness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max= SDVO dependent</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="11" valign="top" >armada</td>
+       <td rowspan="2" valign="top" >CRTC</td>
+       <td valign="top" >"CSC_YUV"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "Auto" , "CCIR601", "CCIR709" }</td>
+       <td valign="top" >CRTC</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"CSC_RGB"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "Auto", "Computer system", "Studio" }</td>
+       <td valign="top" >CRTC</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="9" valign="top" >Overlay</td>
+       <td valign="top" >"colorkey"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"colorkey_min"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"colorkey_max"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"colorkey_val"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"colorkey_alpha"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0xffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"colorkey_mode"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "disabled", "Y component", "U component"
+       , "V component", "RGB", “R component", "G component", "B component" }</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"brightness"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=256 + 255</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"contrast"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0x7fff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"saturation"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0x7fff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="2" valign="top" >exynos</td>
+       <td valign="top" >CRTC</td>
+       <td valign="top" >“mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "normal", "blank" }</td>
+       <td valign="top" >CRTC</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >Overlay</td>
+       <td valign="top" >“zpos”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=MAX_PLANE-1</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="2" valign="top" >i2c/ch7006_drv</td>
+       <td valign="top" >Generic</td>
+       <td valign="top" >“scale”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=2</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="1" valign="top" >TV</td>
+       <td valign="top" >“mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "PAL", "PAL-M","PAL-N"}, ”PAL-Nc"
+       , "PAL-60", "NTSC-M", "NTSC-J" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="15" valign="top" >nouveau</td>
+       <td rowspan="6" valign="top" >NV10 Overlay</td>
+       <td valign="top" >"colorkey"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0x01ffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“contrast”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=8192-1</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“brightness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1024</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“hue”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=359</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“saturation”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=8192-1</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“iturbt_709”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="2" valign="top" >Nv04 Overlay</td>
+       <td valign="top" >“colorkey”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0x01ffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“brightness”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1024</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="7" valign="top" >Display</td>
+       <td valign="top" >“dithering mode”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "auto", "off", "on" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“dithering depth”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "auto", "off", "on", "static 2x2", "dynamic 2x2", "temporal" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“underscan”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "auto", "6 bpc", "8 bpc" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“underscan hborder”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=128</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“underscan vborder”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=128</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“vibrant hue”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=180</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >“color vibrance”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=200</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >omap</td>
+       <td valign="top" >Generic</td>
+       <td valign="top" >“zorder”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=3</td>
+       <td valign="top" >CRTC, Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >qxl</td>
+       <td valign="top" >Generic</td>
+       <td valign="top" >“hotplug_mode_update"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="9" valign="top" >radeon</td>
+       <td valign="top" >DVI-I</td>
+       <td valign="top" >“coherent”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >DAC enable load detect</td>
+       <td valign="top" >“load detection”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=1</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >TV Standard</td>
+       <td valign="top" >"tv standard"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "ntsc", "pal", "pal-m", "pal-60", "ntsc-j"
+       , "scart-pal", "pal-cn", "secam" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >legacy TMDS PLL detect</td>
+       <td valign="top" >"tmds_pll"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "driver", "bios" }</td>
+       <td valign="top" >-</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="3" valign="top" >Underscan</td>
+       <td valign="top" >"underscan"</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "off", "on", "auto" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"underscan hborder"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=128</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"underscan vborder"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=128</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >Audio</td>
+       <td valign="top" >“audio”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "off", "on", "auto" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >FMT Dithering</td>
+       <td valign="top" >“dither”</td>
+       <td valign="top" >ENUM</td>
+       <td valign="top" >{ "off", "on" }</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td rowspan="3" valign="top" >rcar-du</td>
+       <td rowspan="3" valign="top" >Generic</td>
+       <td valign="top" >"alpha"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=255</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"colorkey"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=0x01ffffff</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       <tr>
+       <td valign="top" >"zpos"</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=1, Max=7</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >TBD</td>
+       </tr>
+       </tbody>
+       </table>
+     </sect2>
+   </sect1>
+   <!-- Internals: vertical blanking -->
+   <sect1 id="drm-vertical-blank">
+     <title>Vertical Blanking</title>
+     <para>
+       Vertical blanking plays a major role in graphics rendering. To achieve
+       tear-free display, users must synchronize page flips and/or rendering to
+       vertical blanking. The DRM API offers ioctls to perform page flips
+       synchronized to vertical blanking and wait for vertical blanking.
+     </para>
+     <para>
+       The DRM core handles most of the vertical blanking management logic, which
+       involves filtering out spurious interrupts, keeping race-free blanking
+       counters, coping with counter wrap-around and resets and keeping use
+       counts. It relies on the driver to generate vertical blanking interrupts
+       and optionally provide a hardware vertical blanking counter. Drivers must
+       implement the following operations.
+     </para>
+     <itemizedlist>
+       <listitem>
+         <synopsis>int (*enable_vblank) (struct drm_device *dev, int crtc);
+ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis>
+         <para>
+         Enable or disable vertical blanking interrupts for the given CRTC.
+       </para>
+       </listitem>
+       <listitem>
+         <synopsis>u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);</synopsis>
+         <para>
+         Retrieve the value of the vertical blanking counter for the given
+         CRTC. If the hardware maintains a vertical blanking counter its value
+         should be returned. Otherwise drivers can use the
+         <function>drm_vblank_count</function> helper function to handle this
+         operation.
+       </para>
+       </listitem>
+     </itemizedlist>
+     <para>
+       Drivers must initialize the vertical blanking handling core with a call to
+       <function>drm_vblank_init</function> in their
+       <methodname>load</methodname> operation. The function will set the struct
+       <structname>drm_device</structname>
+       <structfield>vblank_disable_allowed</structfield> field to 0. This will
+       keep vertical blanking interrupts enabled permanently until the first mode
+       set operation, where <structfield>vblank_disable_allowed</structfield> is
+       set to 1. The reason behind this is not clear. Drivers can set the field
+       to 1 after <function>calling drm_vblank_init</function> to make vertical
+       blanking interrupts dynamically managed from the beginning.
+     </para>
+     <para>
+       Vertical blanking interrupts can be enabled by the DRM core or by drivers
+       themselves (for instance to handle page flipping operations). The DRM core
+       maintains a vertical blanking use count to ensure that the interrupts are
+       not disabled while a user still needs them. To increment the use count,
+       drivers call <function>drm_vblank_get</function>. Upon return vertical
+       blanking interrupts are guaranteed to be enabled.
+     </para>
+     <para>
+       To decrement the use count drivers call
+       <function>drm_vblank_put</function>. Only when the use count drops to zero
+       will the DRM core disable the vertical blanking interrupts after a delay
+       by scheduling a timer. The delay is accessible through the vblankoffdelay
+       module parameter or the <varname>drm_vblank_offdelay</varname> global
+       variable and expressed in milliseconds. Its default value is 5000 ms.
+       Zero means never disable, and a negative value means disable immediately.
+       Drivers may override the behaviour by setting the
+       <structname>drm_device</structname>
+       <structfield>vblank_disable_immediate</structfield> flag, which when set
+       causes vblank interrupts to be disabled immediately regardless of the
+       drm_vblank_offdelay value. The flag should only be set if there's a
+       properly working hardware vblank counter present.
+     </para>
+     <para>
+       When a vertical blanking interrupt occurs drivers only need to call the
+       <function>drm_handle_vblank</function> function to account for the
+       interrupt.
+     </para>
+     <para>
+       Resources allocated by <function>drm_vblank_init</function> must be freed
+       with a call to <function>drm_vblank_cleanup</function> in the driver
+       <methodname>unload</methodname> operation handler.
+     </para>
+     <sect2>
+       <title>Vertical Blanking and Interrupt Handling Functions Reference</title>
+ !Edrivers/gpu/drm/drm_irq.c
+ !Finclude/drm/drmP.h drm_crtc_vblank_waitqueue
+     </sect2>
+   </sect1>
+   <!-- Internals: open/close, file operations and ioctls -->
+   <sect1>
+     <title>Open/Close, File Operations and IOCTLs</title>
+     <sect2>
+       <title>Open and Close</title>
+       <synopsis>int (*firstopen) (struct drm_device *);
+ void (*lastclose) (struct drm_device *);
+ int (*open) (struct drm_device *, struct drm_file *);
+ void (*preclose) (struct drm_device *, struct drm_file *);
+ void (*postclose) (struct drm_device *, struct drm_file *);</synopsis>
+       <abstract>Open and close handlers. None of those methods are mandatory.
+       </abstract>
+       <para>
+         The <methodname>firstopen</methodname> method is called by the DRM core
+       for legacy UMS (User Mode Setting) drivers only when an application
+       opens a device that has no other opened file handle. UMS drivers can
+       implement it to acquire device resources. KMS drivers can't use the
+       method and must acquire resources in the <methodname>load</methodname>
+       method instead.
+       </para>
+       <para>
+       Similarly the <methodname>lastclose</methodname> method is called when
+       the last application holding a file handle opened on the device closes
+       it, for both UMS and KMS drivers. Additionally, the method is also
+       called at module unload time or, for hot-pluggable devices, when the
+       device is unplugged. The <methodname>firstopen</methodname> and
+       <methodname>lastclose</methodname> calls can thus be unbalanced.
+       </para>
+       <para>
+         The <methodname>open</methodname> method is called every time the device
+       is opened by an application. Drivers can allocate per-file private data
+       in this method and store them in the struct
+       <structname>drm_file</structname> <structfield>driver_priv</structfield>
+       field. Note that the <methodname>open</methodname> method is called
+       before <methodname>firstopen</methodname>.
+       </para>
+       <para>
+         The close operation is split into <methodname>preclose</methodname> and
+       <methodname>postclose</methodname> methods. Drivers must stop and
+       cleanup all per-file operations in the <methodname>preclose</methodname>
+       method. For instance pending vertical blanking and page flip events must
+       be cancelled. No per-file operation is allowed on the file handle after
+       returning from the <methodname>preclose</methodname> method.
+       </para>
+       <para>
+         Finally the <methodname>postclose</methodname> method is called as the
+       last step of the close operation, right before calling the
+       <methodname>lastclose</methodname> method if no other open file handle
+       exists for the device. Drivers that have allocated per-file private data
+       in the <methodname>open</methodname> method should free it here.
+       </para>
+       <para>
+         The <methodname>lastclose</methodname> method should restore CRTC and
+       plane properties to default value, so that a subsequent open of the
+       device will not inherit state from the previous user. It can also be
+       used to execute delayed power switching state changes, e.g. in
+       conjunction with the vga_switcheroo infrastructure (see
+       <xref linkend="vga_switcheroo"/>). Beyond that KMS drivers should not
+       do any further cleanup. Only legacy UMS drivers might need to clean up
+       device state so that the vga console or an independent fbdev driver
+       could take over.
+       </para>
+     </sect2>
+     <sect2>
+       <title>File Operations</title>
+       <synopsis>const struct file_operations *fops</synopsis>
+       <abstract>File operations for the DRM device node.</abstract>
+       <para>
+         Drivers must define the file operations structure that forms the DRM
+       userspace API entry point, even though most of those operations are
+       implemented in the DRM core. The <methodname>open</methodname>,
+       <methodname>release</methodname> and <methodname>ioctl</methodname>
+       operations are handled by
+       <programlisting>
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .release = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+   #ifdef CONFIG_COMPAT
+       .compat_ioctl = drm_compat_ioctl,
+   #endif
+         </programlisting>
+       </para>
+       <para>
+         Drivers that implement private ioctls that requires 32/64bit
+       compatibility support must provide their own
+       <methodname>compat_ioctl</methodname> handler that processes private
+       ioctls and calls <function>drm_compat_ioctl</function> for core ioctls.
+       </para>
+       <para>
+         The <methodname>read</methodname> and <methodname>poll</methodname>
+       operations provide support for reading DRM events and polling them. They
+       are implemented by
+       <programlisting>
+       .poll = drm_poll,
+       .read = drm_read,
+       .llseek = no_llseek,
+       </programlisting>
+       </para>
+       <para>
+         The memory mapping implementation varies depending on how the driver
+       manages memory. Pre-GEM drivers will use <function>drm_mmap</function>,
+       while GEM-aware drivers will use <function>drm_gem_mmap</function>. See
+       <xref linkend="drm-gem"/>.
+       <programlisting>
+       .mmap = drm_gem_mmap,
+       </programlisting>
+       </para>
+       <para>
+         No other file operation is supported by the DRM API.
+       </para>
+     </sect2>
+     <sect2>
+       <title>IOCTLs</title>
+       <synopsis>struct drm_ioctl_desc *ioctls;
+ int num_ioctls;</synopsis>
+       <abstract>Driver-specific ioctls descriptors table.</abstract>
+       <para>
+         Driver-specific ioctls numbers start at DRM_COMMAND_BASE. The ioctls
+       descriptors table is indexed by the ioctl number offset from the base
+       value. Drivers can use the DRM_IOCTL_DEF_DRV() macro to initialize the
+       table entries.
+       </para>
+       <para>
+         <programlisting>DRM_IOCTL_DEF_DRV(ioctl, func, flags)</programlisting>
+       <para>
+         <parameter>ioctl</parameter> is the ioctl name. Drivers must define
+         the DRM_##ioctl and DRM_IOCTL_##ioctl macros to the ioctl number
+         offset from DRM_COMMAND_BASE and the ioctl number respectively. The
+         first macro is private to the device while the second must be exposed
+         to userspace in a public header.
+       </para>
+       <para>
+         <parameter>func</parameter> is a pointer to the ioctl handler function
+         compatible with the <type>drm_ioctl_t</type> type.
+         <programlisting>typedef int drm_ioctl_t(struct drm_device *dev, void *data,
+               struct drm_file *file_priv);</programlisting>
+       </para>
+       <para>
+         <parameter>flags</parameter> is a bitmask combination of the following
+         values. It restricts how the ioctl is allowed to be called.
+         <itemizedlist>
+           <listitem><para>
+             DRM_AUTH - Only authenticated callers allowed
+           </para></listitem>
+           <listitem><para>
+             DRM_MASTER - The ioctl can only be called on the master file
+             handle
+           </para></listitem>
+             <listitem><para>
+             DRM_ROOT_ONLY - Only callers with the SYSADMIN capability allowed
+           </para></listitem>
+             <listitem><para>
+             DRM_CONTROL_ALLOW - The ioctl can only be called on a control
+             device
+           </para></listitem>
+             <listitem><para>
+             DRM_UNLOCKED - The ioctl handler will be called without locking
+             the DRM global mutex. This is the enforced default for kms drivers
+             (i.e. using the DRIVER_MODESET flag) and hence shouldn't be used
+             any more for new drivers.
+           </para></listitem>
+         </itemizedlist>
+       </para>
+       </para>
+ !Edrivers/gpu/drm/drm_ioctl.c
+     </sect2>
+   </sect1>
+   <sect1>
+     <title>Legacy Support Code</title>
+     <para>
+       The section very briefly covers some of the old legacy support code which
+       is only used by old DRM drivers which have done a so-called shadow-attach
+       to the underlying device instead of registering as a real driver. This
+       also includes some of the old generic buffer management and command
+       submission code. Do not use any of this in new and modern drivers.
+     </para>
+     <sect2>
+       <title>Legacy Suspend/Resume</title>
+       <para>
+       The DRM core provides some suspend/resume code, but drivers wanting full
+       suspend/resume support should provide save() and restore() functions.
+       These are called at suspend, hibernate, or resume time, and should perform
+       any state save or restore required by your device across suspend or
+       hibernate states.
+       </para>
+       <synopsis>int (*suspend) (struct drm_device *, pm_message_t state);
+   int (*resume) (struct drm_device *);</synopsis>
+       <para>
+       Those are legacy suspend and resume methods which
+       <emphasis>only</emphasis> work with the legacy shadow-attach driver
+       registration functions. New driver should use the power management
+       interface provided by their bus type (usually through
+       the struct <structname>device_driver</structname> dev_pm_ops) and set
+       these methods to NULL.
+       </para>
+     </sect2>
+     <sect2>
+       <title>Legacy DMA Services</title>
+       <para>
+       This should cover how DMA mapping etc. is supported by the core.
+       These functions are deprecated and should not be used.
+       </para>
+     </sect2>
+   </sect1>
+   </chapter>
+ <!-- TODO
+ - Add a glossary
+ - Document the struct_mutex catch-all lock
+ - Document connector properties
+ - Why is the load method optional?
+ - What are drivers supposed to set the initial display state to, and how?
+   Connector's DPMS states are not initialized and are thus equal to
+   DRM_MODE_DPMS_ON. The fbcon compatibility layer calls
+   drm_helper_disable_unused_functions(), which disables unused encoders and
+   CRTCs, but doesn't touch the connectors' DPMS state, and
+   drm_helper_connector_dpms() in reaction to fbdev blanking events. Do drivers
+   that don't implement (or just don't use) fbcon compatibility need to call
+   those functions themselves?
+ - KMS drivers must call drm_vblank_pre_modeset() and drm_vblank_post_modeset()
+   around mode setting. Should this be done in the DRM core?
+ - vblank_disable_allowed is set to 1 in the first drm_vblank_post_modeset()
+   call and never set back to 0. It seems to be safe to permanently set it to 1
+   in drm_vblank_init() for KMS driver, and it might be safe for UMS drivers as
+   well. This should be investigated.
+ - crtc and connector .save and .restore operations are only used internally in
+   drivers, should they be removed from the core?
+ - encoder mid-layer .save and .restore operations are only used internally in
+   drivers, should they be removed from the core?
+ - encoder mid-layer .detect operation is only used internally in drivers,
+   should it be removed from the core?
+ -->
+   <!-- External interfaces -->
+   <chapter id="drmExternals">
+     <title>Userland interfaces</title>
+     <para>
+       The DRM core exports several interfaces to applications,
+       generally intended to be used through corresponding libdrm
+       wrapper functions.  In addition, drivers export device-specific
+       interfaces for use by userspace drivers &amp; device-aware
+       applications through ioctls and sysfs files.
+     </para>
+     <para>
+       External interfaces include: memory mapping, context management,
+       DMA operations, AGP management, vblank control, fence
+       management, memory management, and output management.
+     </para>
+     <para>
+       Cover generic ioctls and sysfs layout here.  We only need high-level
+       info, since man pages should cover the rest.
+     </para>
+   <!-- External: render nodes -->
+     <sect1>
+       <title>Render nodes</title>
+       <para>
+         DRM core provides multiple character-devices for user-space to use.
+         Depending on which device is opened, user-space can perform a different
+         set of operations (mainly ioctls). The primary node is always created
+         and called card&lt;num&gt;. Additionally, a currently
+         unused control node, called controlD&lt;num&gt; is also
+         created. The primary node provides all legacy operations and
+         historically was the only interface used by userspace. With KMS, the
+         control node was introduced. However, the planned KMS control interface
+         has never been written and so the control node stays unused to date.
+       </para>
+       <para>
+         With the increased use of offscreen renderers and GPGPU applications,
+         clients no longer require running compositors or graphics servers to
+         make use of a GPU. But the DRM API required unprivileged clients to
+         authenticate to a DRM-Master prior to getting GPU access. To avoid this
+         step and to grant clients GPU access without authenticating, render
+         nodes were introduced. Render nodes solely serve render clients, that
+         is, no modesetting or privileged ioctls can be issued on render nodes.
+         Only non-global rendering commands are allowed. If a driver supports
+         render nodes, it must advertise it via the DRIVER_RENDER
+         DRM driver capability. If not supported, the primary node must be used
+         for render clients together with the legacy drmAuth authentication
+         procedure.
+       </para>
+       <para>
+         If a driver advertises render node support, DRM core will create a
+         separate render node called renderD&lt;num&gt;. There will
+         be one render node per device. No ioctls except  PRIME-related ioctls
+         will be allowed on this node. Especially GEM_OPEN will be
+         explicitly prohibited. Render nodes are designed to avoid the
+         buffer-leaks, which occur if clients guess the flink names or mmap
+         offsets on the legacy interface. Additionally to this basic interface,
+         drivers must mark their driver-dependent render-only ioctls as
+         DRM_RENDER_ALLOW so render clients can use them. Driver
+         authors must be careful not to allow any privileged ioctls on render
+         nodes.
+       </para>
+       <para>
+         With render nodes, user-space can now control access to the render node
+         via basic file-system access-modes. A running graphics server which
+         authenticates clients on the privileged primary/legacy node is no longer
+         required. Instead, a client can open the render node and is immediately
+         granted GPU access. Communication between clients (or servers) is done
+         via PRIME. FLINK from render node to legacy node is not supported. New
+         clients must not use the insecure FLINK interface.
+       </para>
+       <para>
+         Besides dropping all modeset/global ioctls, render nodes also drop the
+         DRM-Master concept. There is no reason to associate render clients with
+         a DRM-Master as they are independent of any graphics server. Besides,
+         they must work without any running master, anyway.
+         Drivers must be able to run without a master object if they support
+         render nodes. If, on the other hand, a driver requires shared state
+         between clients which is visible to user-space and accessible beyond
+         open-file boundaries, they cannot support render nodes.
+       </para>
+     </sect1>
+   <!-- External: vblank handling -->
+     <sect1>
+       <title>VBlank event handling</title>
+       <para>
+         The DRM core exposes two vertical blank related ioctls:
+         <variablelist>
+           <varlistentry>
+             <term>DRM_IOCTL_WAIT_VBLANK</term>
+             <listitem>
+               <para>
+                 This takes a struct drm_wait_vblank structure as its argument,
+                 and it is used to block or request a signal when a specified
+                 vblank event occurs.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>DRM_IOCTL_MODESET_CTL</term>
+             <listitem>
+               <para>
+               This was only used for user-mode-settind drivers around
+               modesetting changes to allow the kernel to update the vblank
+               interrupt after mode setting, since on many devices the vertical
+               blank counter is reset to 0 at some point during modeset. Modern
+               drivers should not call this any more since with kernel mode
+               setting it is a no-op.
+               </para>
+             </listitem>
+           </varlistentry>
+         </variablelist>
+       </para>
+     </sect1>
+   </chapter>
+ </part>
+ <part id="drmDrivers">
+   <title>DRM Drivers</title>
+   <partintro>
+     <para>
+       This second part of the GPU Driver Developer's Guide documents driver
+       code, implementation details and also all the driver-specific userspace
+       interfaces. Especially since all hardware-acceleration interfaces to
+       userspace are driver specific for efficiency and other reasons these
+       interfaces can be rather substantial. Hence every driver has its own
+       chapter.
+     </para>
+   </partintro>
+   <chapter id="drmI915">
+     <title>drm/i915 Intel GFX Driver</title>
+     <para>
+       The drm/i915 driver supports all (with the exception of some very early
+       models) integrated GFX chipsets with both Intel display and rendering
+       blocks. This excludes a set of SoC platforms with an SGX rendering unit,
+       those have basic support through the gma500 drm driver.
+     </para>
+     <sect1>
+       <title>Core Driver Infrastructure</title>
+       <para>
+       This section covers core driver infrastructure used by both the display
+       and the GEM parts of the driver.
+       </para>
+       <sect2>
+         <title>Runtime Power Management</title>
+ !Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
+ !Idrivers/gpu/drm/i915/intel_runtime_pm.c
+ !Idrivers/gpu/drm/i915/intel_uncore.c
+       </sect2>
+       <sect2>
+         <title>Interrupt Handling</title>
+ !Pdrivers/gpu/drm/i915/i915_irq.c interrupt handling
+ !Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_init intel_irq_init_hw intel_hpd_init
+ !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
+ !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
+       </sect2>
+       <sect2>
+         <title>Intel GVT-g Guest Support(vGPU)</title>
+ !Pdrivers/gpu/drm/i915/i915_vgpu.c Intel GVT-g guest support
+ !Idrivers/gpu/drm/i915/i915_vgpu.c
+       </sect2>
+     </sect1>
+     <sect1>
+       <title>Display Hardware Handling</title>
+       <para>
+         This section covers everything related to the display hardware including
+         the mode setting infrastructure, plane, sprite and cursor handling and
+         display, output probing and related topics.
+       </para>
+       <sect2>
+         <title>Mode Setting Infrastructure</title>
+         <para>
+           The i915 driver is thus far the only DRM driver which doesn't use the
+           common DRM helper code to implement mode setting sequences. Thus it
+           has its own tailor-made infrastructure for executing a display
+           configuration change.
+         </para>
+       </sect2>
+       <sect2>
+         <title>Frontbuffer Tracking</title>
+ !Pdrivers/gpu/drm/i915/intel_frontbuffer.c frontbuffer tracking
+ !Idrivers/gpu/drm/i915/intel_frontbuffer.c
+ !Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb
+       </sect2>
+       <sect2>
+         <title>Display FIFO Underrun Reporting</title>
+ !Pdrivers/gpu/drm/i915/intel_fifo_underrun.c fifo underrun handling
+ !Idrivers/gpu/drm/i915/intel_fifo_underrun.c
+       </sect2>
+       <sect2>
+         <title>Plane Configuration</title>
+         <para>
+         This section covers plane configuration and composition with the
+         primary plane, sprites, cursors and overlays. This includes the
+         infrastructure to do atomic vsync'ed updates of all this state and
+         also tightly coupled topics like watermark setup and computation,
+         framebuffer compression and panel self refresh.
+         </para>
+       </sect2>
+       <sect2>
+         <title>Atomic Plane Helpers</title>
+ !Pdrivers/gpu/drm/i915/intel_atomic_plane.c atomic plane helpers
+ !Idrivers/gpu/drm/i915/intel_atomic_plane.c
+       </sect2>
+       <sect2>
+         <title>Output Probing</title>
+         <para>
+         This section covers output probing and related infrastructure like the
+         hotplug interrupt storm detection and mitigation code. Note that the
+         i915 driver still uses most of the common DRM helper code for output
+         probing, so those sections fully apply.
+         </para>
+       </sect2>
+       <sect2>
+         <title>Hotplug</title>
+ !Pdrivers/gpu/drm/i915/intel_hotplug.c Hotplug
+ !Idrivers/gpu/drm/i915/intel_hotplug.c
+       </sect2>
+       <sect2>
+       <title>High Definition Audio</title>
+ !Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port
+ !Idrivers/gpu/drm/i915/intel_audio.c
+ !Iinclude/drm/i915_component.h
+       </sect2>
+       <sect2>
+       <title>Panel Self Refresh PSR (PSR/SRD)</title>
+ !Pdrivers/gpu/drm/i915/intel_psr.c Panel Self Refresh (PSR/SRD)
+ !Idrivers/gpu/drm/i915/intel_psr.c
+       </sect2>
+       <sect2>
+       <title>Frame Buffer Compression (FBC)</title>
+ !Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC)
+ !Idrivers/gpu/drm/i915/intel_fbc.c
+       </sect2>
+       <sect2>
+         <title>Display Refresh Rate Switching (DRRS)</title>
+ !Pdrivers/gpu/drm/i915/intel_dp.c Display Refresh Rate Switching (DRRS)
+ !Fdrivers/gpu/drm/i915/intel_dp.c intel_dp_set_drrs_state
+ !Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_enable
+ !Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_disable
+ !Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_invalidate
+ !Fdrivers/gpu/drm/i915/intel_dp.c intel_edp_drrs_flush
+ !Fdrivers/gpu/drm/i915/intel_dp.c intel_dp_drrs_init
+       </sect2>
+       <sect2>
+         <title>DPIO</title>
+ !Pdrivers/gpu/drm/i915/i915_reg.h DPIO
+       <table id="dpiox2">
+         <title>Dual channel PHY (VLV/CHV/BXT)</title>
+         <tgroup cols="8">
+           <colspec colname="c0" />
+           <colspec colname="c1" />
+           <colspec colname="c2" />
+           <colspec colname="c3" />
+           <colspec colname="c4" />
+           <colspec colname="c5" />
+           <colspec colname="c6" />
+           <colspec colname="c7" />
+           <spanspec spanname="ch0" namest="c0" nameend="c3" />
+           <spanspec spanname="ch1" namest="c4" nameend="c7" />
+           <spanspec spanname="ch0pcs01" namest="c0" nameend="c1" />
+           <spanspec spanname="ch0pcs23" namest="c2" nameend="c3" />
+           <spanspec spanname="ch1pcs01" namest="c4" nameend="c5" />
+           <spanspec spanname="ch1pcs23" namest="c6" nameend="c7" />
+           <thead>
+             <row>
+               <entry spanname="ch0">CH0</entry>
+               <entry spanname="ch1">CH1</entry>
+             </row>
+           </thead>
+           <tbody valign="top" align="center">
+             <row>
+               <entry spanname="ch0">CMN/PLL/REF</entry>
+               <entry spanname="ch1">CMN/PLL/REF</entry>
+             </row>
+             <row>
+               <entry spanname="ch0pcs01">PCS01</entry>
+               <entry spanname="ch0pcs23">PCS23</entry>
+               <entry spanname="ch1pcs01">PCS01</entry>
+               <entry spanname="ch1pcs23">PCS23</entry>
+             </row>
+             <row>
+               <entry>TX0</entry>
+               <entry>TX1</entry>
+               <entry>TX2</entry>
+               <entry>TX3</entry>
+               <entry>TX0</entry>
+               <entry>TX1</entry>
+               <entry>TX2</entry>
+               <entry>TX3</entry>
+             </row>
+             <row>
+               <entry spanname="ch0">DDI0</entry>
+               <entry spanname="ch1">DDI1</entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+       <table id="dpiox1">
+         <title>Single channel PHY (CHV/BXT)</title>
+         <tgroup cols="4">
+           <colspec colname="c0" />
+           <colspec colname="c1" />
+           <colspec colname="c2" />
+           <colspec colname="c3" />
+           <spanspec spanname="ch0" namest="c0" nameend="c3" />
+           <spanspec spanname="ch0pcs01" namest="c0" nameend="c1" />
+           <spanspec spanname="ch0pcs23" namest="c2" nameend="c3" />
+           <thead>
+             <row>
+               <entry spanname="ch0">CH0</entry>
+             </row>
+           </thead>
+           <tbody valign="top" align="center">
+             <row>
+               <entry spanname="ch0">CMN/PLL/REF</entry>
+             </row>
+             <row>
+               <entry spanname="ch0pcs01">PCS01</entry>
+               <entry spanname="ch0pcs23">PCS23</entry>
+             </row>
+             <row>
+               <entry>TX0</entry>
+               <entry>TX1</entry>
+               <entry>TX2</entry>
+               <entry>TX3</entry>
+             </row>
+             <row>
+               <entry spanname="ch0">DDI2</entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+       </sect2>
+       <sect2>
+        <title>CSR firmware support for DMC</title>
+ !Pdrivers/gpu/drm/i915/intel_csr.c csr support for dmc
+ !Idrivers/gpu/drm/i915/intel_csr.c
+       </sect2>
+     </sect1>
+     <sect1>
+       <title>Memory Management and Command Submission</title>
+       <para>
+       This sections covers all things related to the GEM implementation in the
+       i915 driver.
+       </para>
+       <sect2>
+         <title>Batchbuffer Parsing</title>
+ !Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser
+ !Idrivers/gpu/drm/i915/i915_cmd_parser.c
+       </sect2>
+       <sect2>
+         <title>Batchbuffer Pools</title>
+ !Pdrivers/gpu/drm/i915/i915_gem_batch_pool.c batch pool
+ !Idrivers/gpu/drm/i915/i915_gem_batch_pool.c
+       </sect2>
+       <sect2>
+         <title>Logical Rings, Logical Ring Contexts and Execlists</title>
+ !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists
+ !Idrivers/gpu/drm/i915/intel_lrc.c
+       </sect2>
+       <sect2>
+         <title>Global GTT views</title>
+ !Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views
+ !Idrivers/gpu/drm/i915/i915_gem_gtt.c
+       </sect2>
+       <sect2>
+         <title>GTT Fences and Swizzling</title>
+ !Idrivers/gpu/drm/i915/i915_gem_fence.c
+         <sect3>
+           <title>Global GTT Fence Handling</title>
+ !Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling
+         </sect3>
+         <sect3>
+           <title>Hardware Tiling and Swizzling Details</title>
+ !Pdrivers/gpu/drm/i915/i915_gem_fence.c tiling swizzling details
+         </sect3>
+       </sect2>
+       <sect2>
+         <title>Object Tiling IOCTLs</title>
+ !Idrivers/gpu/drm/i915/i915_gem_tiling.c
+ !Pdrivers/gpu/drm/i915/i915_gem_tiling.c buffer object tiling
+       </sect2>
+       <sect2>
+         <title>Buffer Object Eviction</title>
+       <para>
+         This section documents the interface functions for evicting buffer
+         objects to make space available in the virtual gpu address spaces.
+         Note that this is mostly orthogonal to shrinking buffer objects
+         caches, which has the goal to make main memory (shared with the gpu
+         through the unified memory architecture) available.
+       </para>
+ !Idrivers/gpu/drm/i915/i915_gem_evict.c
+       </sect2>
+       <sect2>
+         <title>Buffer Object Memory Shrinking</title>
+       <para>
+         This section documents the interface function for shrinking memory
+         usage of buffer object caches. Shrinking is used to make main memory
+         available.  Note that this is mostly orthogonal to evicting buffer
+         objects, which has the goal to make space in gpu virtual address
+         spaces.
+       </para>
+ !Idrivers/gpu/drm/i915/i915_gem_shrinker.c
+       </sect2>
+     </sect1>
+     <sect1>
 -        <title>GuC</title>
++      <title>GuC</title>
+       <sect2>
 -        <title>GuC Client</title>
 -!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submissison
++        <title>GuC-specific firmware loader</title>
+ !Pdrivers/gpu/drm/i915/intel_guc_loader.c GuC-specific firmware loader
+ !Idrivers/gpu/drm/i915/intel_guc_loader.c
+       </sect2>
+       <sect2>
++        <title>GuC-based command submission</title>
++!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submission
+ !Idrivers/gpu/drm/i915/i915_guc_submission.c
+       </sect2>
++      <sect2>
++        <title>GuC Firmware Layout</title>
++!Pdrivers/gpu/drm/i915/intel_guc_fwif.h GuC Firmware Layout
++      </sect2>
+     </sect1>
+     <sect1>
+       <title> Tracing </title>
+       <para>
+     This sections covers all things related to the tracepoints implemented in
+     the i915 driver.
+       </para>
+       <sect2>
+         <title> i915_ppgtt_create and i915_ppgtt_release </title>
+ !Pdrivers/gpu/drm/i915/i915_trace.h i915_ppgtt_create and i915_ppgtt_release tracepoints
+       </sect2>
+       <sect2>
+         <title> i915_context_create and i915_context_free </title>
+ !Pdrivers/gpu/drm/i915/i915_trace.h i915_context_create and i915_context_free tracepoints
+       </sect2>
+       <sect2>
+         <title> switch_mm </title>
+ !Pdrivers/gpu/drm/i915/i915_trace.h switch_mm tracepoint
+       </sect2>
+     </sect1>
+   </chapter>
+ !Cdrivers/gpu/drm/i915/i915_irq.c
+ </part>
+ <part id="vga_switcheroo">
+   <title>vga_switcheroo</title>
+   <partintro>
+ !Pdrivers/gpu/vga/vga_switcheroo.c Overview
+   </partintro>
+   <chapter id="modes_of_use">
+     <title>Modes of Use</title>
+   <sect1>
+     <title>Manual switching and manual power control</title>
+ !Pdrivers/gpu/vga/vga_switcheroo.c Manual switching and manual power control
+   </sect1>
+   <sect1>
+     <title>Driver power control</title>
+ !Pdrivers/gpu/vga/vga_switcheroo.c Driver power control
+   </sect1>
+   </chapter>
+   <chapter id="pubfunctions">
+     <title>Public functions</title>
+ !Edrivers/gpu/vga/vga_switcheroo.c
+   </chapter>
+   <chapter id="pubstructures">
+     <title>Public structures</title>
+ !Finclude/linux/vga_switcheroo.h vga_switcheroo_handler
+ !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_ops
+   </chapter>
+   <chapter id="pubconstants">
+     <title>Public constants</title>
+ !Finclude/linux/vga_switcheroo.h vga_switcheroo_client_id
+ !Finclude/linux/vga_switcheroo.h vga_switcheroo_state
+   </chapter>
+   <chapter id="privstructures">
+     <title>Private structures</title>
+ !Fdrivers/gpu/vga/vga_switcheroo.c vgasr_priv
+ !Fdrivers/gpu/vga/vga_switcheroo.c vga_switcheroo_client
+   </chapter>
+ !Cdrivers/gpu/vga/vga_switcheroo.c
+ !Cinclude/linux/vga_switcheroo.h
+ </part>
+ </book>
@@@ -547,7 -547,6 +547,7 @@@ static const struct pci_device_id intel
        INTEL_CHV_IDS(&chv_stolen_funcs),
        INTEL_SKL_IDS(&gen9_stolen_funcs),
        INTEL_BXT_IDS(&gen9_stolen_funcs),
 +      INTEL_KBL_IDS(&gen9_stolen_funcs),
  };
  
  static void __init intel_graphics_stolen(int num, int slot, int func)
  static void __init force_disable_hpet(int num, int slot, int func)
  {
  #ifdef CONFIG_HPET_TIMER
-       boot_hpet_disable = 1;
+       boot_hpet_disable = true;
        pr_info("x86/hpet: Will disable the HPET for this platform because it's not reliable\n");
  #endif
  }
@@@ -956,7 -956,6 +956,6 @@@ static int i915_gem_fence_regs_info(str
        if (ret)
                return ret;
  
-       seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
        seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
@@@ -1253,21 -1252,18 +1252,21 @@@ static int i915_frequency_info(struct s
  
                max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 :
                            rp_state_cap >> 16) & 0xff;
 -              max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
 +              max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
 +                           GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
  
                max_freq = (rp_state_cap & 0xff00) >> 8;
 -              max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
 +              max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
 +                           GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
  
                max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 :
                            rp_state_cap >> 0) & 0xff;
 -              max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1);
 +              max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
 +                           GEN9_FREQ_SCALER : 1);
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, max_freq));
                seq_printf(m, "Max overclocked frequency: %dMHz\n",
@@@ -1527,7 -1523,7 +1526,7 @@@ static int gen6_drpc_info(struct seq_fi
                seq_printf(m, "RC information accurate: %s\n", yesno(count < 51));
        }
  
 -      gt_core_status = readl(dev_priv->regs + GEN6_GT_CORE_STATUS);
 +      gt_core_status = I915_READ_FW(GEN6_GT_CORE_STATUS);
        trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4, true);
  
        rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
@@@ -1644,7 -1640,7 +1643,7 @@@ static int i915_fbc_status(struct seq_f
                seq_puts(m, "FBC enabled\n");
        else
                seq_printf(m, "FBC disabled: %s\n",
 -                        intel_no_fbc_reason_str(dev_priv->fbc.no_fbc_reason));
 +                         dev_priv->fbc.no_fbc_reason);
  
        if (INTEL_INFO(dev_priv)->gen >= 7)
                seq_printf(m, "Compressing: %s\n",
@@@ -1805,7 -1801,7 +1804,7 @@@ static int i915_ring_freq_table(struct 
        if (ret)
                goto out;
  
 -      if (IS_SKYLAKE(dev)) {
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                /* Convert GT frequency to 50 HZ units */
                min_gpu_freq =
                        dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER;
                                       &ia_freq);
                seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
                           intel_gpu_freq(dev_priv, (gpu_freq *
 -                              (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1))),
 +                              (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ?
 +                               GEN9_FREQ_SCALER : 1))),
                           ((ia_freq >> 0) & 0xff) * 100,
                           ((ia_freq >> 8) & 0xff) * 100);
        }
@@@ -1878,19 -1873,17 +1877,19 @@@ static int i915_gem_framebuffer_info(st
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        ifbdev = dev_priv->fbdev;
 -      fb = to_intel_framebuffer(ifbdev->helper.fb);
 -
 -      seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
 -                 fb->base.width,
 -                 fb->base.height,
 -                 fb->base.depth,
 -                 fb->base.bits_per_pixel,
 -                 fb->base.modifier[0],
 -                 atomic_read(&fb->base.refcount.refcount));
 -      describe_obj(m, fb->obj);
 -      seq_putc(m, '\n');
 +      if (ifbdev) {
 +              fb = to_intel_framebuffer(ifbdev->helper.fb);
 +
 +              seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ",
 +                         fb->base.width,
 +                         fb->base.height,
 +                         fb->base.depth,
 +                         fb->base.bits_per_pixel,
 +                         fb->base.modifier[0],
 +                         atomic_read(&fb->base.refcount.refcount));
 +              describe_obj(m, fb->obj);
 +              seq_putc(m, '\n');
 +      }
  #endif
  
        mutex_lock(&dev->mode_config.fb_lock);
@@@ -2409,12 -2402,6 +2408,12 @@@ static int i915_guc_load_status_info(st
                guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
        seq_printf(m, "\tversion found: %d.%d\n",
                guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found);
 +      seq_printf(m, "\theader: offset is %d; size = %d\n",
 +              guc_fw->header_offset, guc_fw->header_size);
 +      seq_printf(m, "\tuCode: offset is %d; size = %d\n",
 +              guc_fw->ucode_offset, guc_fw->ucode_size);
 +      seq_printf(m, "\tRSA: offset is %d; size = %d\n",
 +              guc_fw->rsa_offset, guc_fw->rsa_size);
  
        tmp = I915_READ(GUC_STATUS);
  
@@@ -2563,7 -2550,7 +2562,7 @@@ static int i915_edp_psr_status(struct s
                   yesno(work_busy(&dev_priv->psr.work.work)));
  
        if (HAS_DDI(dev))
 -              enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
 +              enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
        else {
                for_each_pipe(dev_priv, pipe) {
                        stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
  
        /* CHV PSR has no kind of performance counter */
        if (HAS_DDI(dev)) {
 -              psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 +              psrperf = I915_READ(EDP_PSR_PERF_CNT) &
                        EDP_PSR_PERF_CNT_MASK;
  
                seq_printf(m, "Performance_Counter: %u\n", psrperf);
@@@ -2709,16 -2696,24 +2708,16 @@@ static const char *power_domain_str(enu
                return "TRANSCODER_C";
        case POWER_DOMAIN_TRANSCODER_EDP:
                return "TRANSCODER_EDP";
 -      case POWER_DOMAIN_PORT_DDI_A_2_LANES:
 -              return "PORT_DDI_A_2_LANES";
 -      case POWER_DOMAIN_PORT_DDI_A_4_LANES:
 -              return "PORT_DDI_A_4_LANES";
 -      case POWER_DOMAIN_PORT_DDI_B_2_LANES:
 -              return "PORT_DDI_B_2_LANES";
 -      case POWER_DOMAIN_PORT_DDI_B_4_LANES:
 -              return "PORT_DDI_B_4_LANES";
 -      case POWER_DOMAIN_PORT_DDI_C_2_LANES:
 -              return "PORT_DDI_C_2_LANES";
 -      case POWER_DOMAIN_PORT_DDI_C_4_LANES:
 -              return "PORT_DDI_C_4_LANES";
 -      case POWER_DOMAIN_PORT_DDI_D_2_LANES:
 -              return "PORT_DDI_D_2_LANES";
 -      case POWER_DOMAIN_PORT_DDI_D_4_LANES:
 -              return "PORT_DDI_D_4_LANES";
 -      case POWER_DOMAIN_PORT_DDI_E_2_LANES:
 -              return "PORT_DDI_E_2_LANES";
 +      case POWER_DOMAIN_PORT_DDI_A_LANES:
 +              return "PORT_DDI_A_LANES";
 +      case POWER_DOMAIN_PORT_DDI_B_LANES:
 +              return "PORT_DDI_B_LANES";
 +      case POWER_DOMAIN_PORT_DDI_C_LANES:
 +              return "PORT_DDI_C_LANES";
 +      case POWER_DOMAIN_PORT_DDI_D_LANES:
 +              return "PORT_DDI_D_LANES";
 +      case POWER_DOMAIN_PORT_DDI_E_LANES:
 +              return "PORT_DDI_E_LANES";
        case POWER_DOMAIN_PORT_DSI:
                return "PORT_DSI";
        case POWER_DOMAIN_PORT_CRT:
                return "AUX_C";
        case POWER_DOMAIN_AUX_D:
                return "AUX_D";
 +      case POWER_DOMAIN_GMBUS:
 +              return "GMBUS";
 +      case POWER_DOMAIN_MODESET:
 +              return "MODESET";
        case POWER_DOMAIN_INIT:
                return "INIT";
        default:
@@@ -2786,51 -2777,6 +2785,51 @@@ static int i915_power_domain_info(struc
        return 0;
  }
  
 +static int i915_dmc_info(struct seq_file *m, void *unused)
 +{
 +      struct drm_info_node *node = m->private;
 +      struct drm_device *dev = node->minor->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_csr *csr;
 +
 +      if (!HAS_CSR(dev)) {
 +              seq_puts(m, "not supported\n");
 +              return 0;
 +      }
 +
 +      csr = &dev_priv->csr;
 +
 +      intel_runtime_pm_get(dev_priv);
 +
 +      seq_printf(m, "fw loaded: %s\n", yesno(csr->dmc_payload != NULL));
 +      seq_printf(m, "path: %s\n", csr->fw_path);
 +
 +      if (!csr->dmc_payload)
 +              goto out;
 +
 +      seq_printf(m, "version: %d.%d\n", CSR_VERSION_MAJOR(csr->version),
 +                 CSR_VERSION_MINOR(csr->version));
 +
 +      if (IS_SKYLAKE(dev) && csr->version >= CSR_VERSION(1, 6)) {
 +              seq_printf(m, "DC3 -> DC5 count: %d\n",
 +                         I915_READ(SKL_CSR_DC3_DC5_COUNT));
 +              seq_printf(m, "DC5 -> DC6 count: %d\n",
 +                         I915_READ(SKL_CSR_DC5_DC6_COUNT));
 +      } else if (IS_BROXTON(dev) && csr->version >= CSR_VERSION(1, 4)) {
 +              seq_printf(m, "DC3 -> DC5 count: %d\n",
 +                         I915_READ(BXT_CSR_DC3_DC5_COUNT));
 +      }
 +
 +out:
 +      seq_printf(m, "program base: 0x%08x\n", I915_READ(CSR_PROGRAM(0)));
 +      seq_printf(m, "ssp base: 0x%08x\n", I915_READ(CSR_SSP_BASE));
 +      seq_printf(m, "htp: 0x%08x\n", I915_READ(CSR_HTP_SKL));
 +
 +      intel_runtime_pm_put(dev_priv);
 +
 +      return 0;
 +}
 +
  static void intel_seq_print_mode(struct seq_file *m, int tabs,
                                 struct drm_display_mode *mode)
  {
@@@ -2998,107 -2944,6 +2997,107 @@@ static bool cursor_position(struct drm_
        return cursor_active(dev, pipe);
  }
  
 +static const char *plane_type(enum drm_plane_type type)
 +{
 +      switch (type) {
 +      case DRM_PLANE_TYPE_OVERLAY:
 +              return "OVL";
 +      case DRM_PLANE_TYPE_PRIMARY:
 +              return "PRI";
 +      case DRM_PLANE_TYPE_CURSOR:
 +              return "CUR";
 +      /*
 +       * Deliberately omitting default: to generate compiler warnings
 +       * when a new drm_plane_type gets added.
 +       */
 +      }
 +
 +      return "unknown";
 +}
 +
 +static const char *plane_rotation(unsigned int rotation)
 +{
 +      static char buf[48];
 +      /*
 +       * According to doc only one DRM_ROTATE_ is allowed but this
 +       * will print them all to visualize if the values are misused
 +       */
 +      snprintf(buf, sizeof(buf),
 +               "%s%s%s%s%s%s(0x%08x)",
 +               (rotation & BIT(DRM_ROTATE_0)) ? "0 " : "",
 +               (rotation & BIT(DRM_ROTATE_90)) ? "90 " : "",
 +               (rotation & BIT(DRM_ROTATE_180)) ? "180 " : "",
 +               (rotation & BIT(DRM_ROTATE_270)) ? "270 " : "",
 +               (rotation & BIT(DRM_REFLECT_X)) ? "FLIPX " : "",
 +               (rotation & BIT(DRM_REFLECT_Y)) ? "FLIPY " : "",
 +               rotation);
 +
 +      return buf;
 +}
 +
 +static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 +{
 +      struct drm_info_node *node = m->private;
 +      struct drm_device *dev = node->minor->dev;
 +      struct intel_plane *intel_plane;
 +
 +      for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
 +              struct drm_plane_state *state;
 +              struct drm_plane *plane = &intel_plane->base;
 +
 +              if (!plane->state) {
 +                      seq_puts(m, "plane->state is NULL!\n");
 +                      continue;
 +              }
 +
 +              state = plane->state;
 +
 +              seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n",
 +                         plane->base.id,
 +                         plane_type(intel_plane->base.type),
 +                         state->crtc_x, state->crtc_y,
 +                         state->crtc_w, state->crtc_h,
 +                         (state->src_x >> 16),
 +                         ((state->src_x & 0xffff) * 15625) >> 10,
 +                         (state->src_y >> 16),
 +                         ((state->src_y & 0xffff) * 15625) >> 10,
 +                         (state->src_w >> 16),
 +                         ((state->src_w & 0xffff) * 15625) >> 10,
 +                         (state->src_h >> 16),
 +                         ((state->src_h & 0xffff) * 15625) >> 10,
 +                         state->fb ? drm_get_format_name(state->fb->pixel_format) : "N/A",
 +                         plane_rotation(state->rotation));
 +      }
 +}
 +
 +static void intel_scaler_info(struct seq_file *m, struct intel_crtc *intel_crtc)
 +{
 +      struct intel_crtc_state *pipe_config;
 +      int num_scalers = intel_crtc->num_scalers;
 +      int i;
 +
 +      pipe_config = to_intel_crtc_state(intel_crtc->base.state);
 +
 +      /* Not all platformas have a scaler */
 +      if (num_scalers) {
 +              seq_printf(m, "\tnum_scalers=%d, scaler_users=%x scaler_id=%d",
 +                         num_scalers,
 +                         pipe_config->scaler_state.scaler_users,
 +                         pipe_config->scaler_state.scaler_id);
 +
 +              for (i = 0; i < SKL_NUM_SCALERS; i++) {
 +                      struct intel_scaler *sc =
 +                                      &pipe_config->scaler_state.scalers[i];
 +
 +                      seq_printf(m, ", scalers[%d]: use=%s, mode=%x",
 +                                 i, yesno(sc->in_use), sc->mode);
 +              }
 +              seq_puts(m, "\n");
 +      } else {
 +              seq_puts(m, "\tNo scalers available on this platform\n");
 +      }
 +}
 +
  static int i915_display_info(struct seq_file *m, void *unused)
  {
        struct drm_info_node *node = m->private;
  
                pipe_config = to_intel_crtc_state(crtc->base.state);
  
 -              seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n",
 +              seq_printf(m, "CRTC %d: pipe: %c, active=%s, (size=%dx%d), dither=%s, bpp=%d\n",
                           crtc->base.base.id, pipe_name(crtc->pipe),
                           yesno(pipe_config->base.active),
 -                         pipe_config->pipe_src_w, pipe_config->pipe_src_h);
 +                         pipe_config->pipe_src_w, pipe_config->pipe_src_h,
 +                         yesno(pipe_config->dither), pipe_config->pipe_bpp);
 +
                if (pipe_config->base.active) {
                        intel_crtc_info(m, crtc);
  
                                   x, y, crtc->base.cursor->state->crtc_w,
                                   crtc->base.cursor->state->crtc_h,
                                   crtc->cursor_addr, yesno(active));
 +                      intel_scaler_info(m, crtc);
 +                      intel_plane_info(m, crtc);
                }
  
                seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s \n",
@@@ -3269,8 -3110,7 +3268,8 @@@ static int i915_wa_registers(struct seq
  
        seq_printf(m, "Workarounds applied: %d\n", dev_priv->workarounds.count);
        for (i = 0; i < dev_priv->workarounds.count; ++i) {
 -              u32 addr, mask, value, read;
 +              i915_reg_t addr;
 +              u32 mask, value, read;
                bool ok;
  
                addr = dev_priv->workarounds.reg[i].addr;
                read = I915_READ(addr);
                ok = (value & mask) == (read & mask);
                seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X, read: 0x%08x, status: %s\n",
 -                         addr, value, mask, read, ok ? "OK" : "FAIL");
 +                         i915_mmio_reg_offset(addr), value, mask, read, ok ? "OK" : "FAIL");
        }
  
        intel_runtime_pm_put(dev_priv);
@@@ -5183,7 -5023,7 +5182,7 @@@ static void gen9_sseu_device_status(str
  
                stat->slice_total++;
  
 -              if (IS_SKYLAKE(dev))
 +              if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                        ss_cnt = INTEL_INFO(dev)->subslice_per_slice;
  
                for (ss = 0; ss < ss_max; ss++) {
@@@ -5396,7 -5236,6 +5395,7 @@@ static const struct drm_info_list i915_
        {"i915_energy_uJ", i915_energy_uJ, 0},
        {"i915_runtime_pm_status", i915_runtime_pm_status, 0},
        {"i915_power_domain_info", i915_power_domain_info, 0},
 +      {"i915_dmc_info", i915_dmc_info, 0},
        {"i915_display_info", i915_display_info, 0},
        {"i915_semaphore_status", i915_semaphore_status, 0},
        {"i915_shared_dplls_info", i915_shared_dplls_info, 0},
@@@ -28,6 -28,7 +28,6 @@@
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
 -#include <linux/async.h>
  #include <drm/drmP.h>
  #include <drm/drm_crtc_helper.h>
  #include <drm/drm_fb_helper.h>
@@@ -74,7 -75,7 +74,7 @@@ static int i915_getparam(struct drm_dev
                value = 1;
                break;
        case I915_PARAM_NUM_FENCES_AVAIL:
-               value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
+               value = dev_priv->num_fence_regs;
                break;
        case I915_PARAM_HAS_OVERLAY:
                value = dev_priv->overlay ? 1 : 0;
        return 0;
  }
  
- static int i915_setparam(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv)
- {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       drm_i915_setparam_t *param = data;
-       switch (param->param) {
-       case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
-       case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
-       case I915_SETPARAM_ALLOW_BATCHBUFFER:
-               /* Reject all old ums/dri params. */
-               return -ENODEV;
-       case I915_SETPARAM_NUM_USED_FENCES:
-               if (param->value > dev_priv->num_fence_regs ||
-                   param->value < 0)
-                       return -EINVAL;
-               /* Userspace can use first N regs */
-               dev_priv->fence_reg_start = param->value;
-               break;
-       default:
-               DRM_DEBUG_DRIVER("unknown parameter %d\n",
-                                       param->param);
-               return -EINVAL;
-       }
-       return 0;
- }
  static int i915_get_bridge_dev(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@@ -366,7 -338,7 +337,7 @@@ static void i915_switcheroo_set_state(s
                i915_resume_switcheroo(dev);
                dev->switch_power_state = DRM_SWITCH_POWER_ON;
        } else {
 -              pr_err("switched off\n");
 +              pr_info("switched off\n");
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
                i915_suspend_switcheroo(dev, pmm);
                dev->switch_power_state = DRM_SWITCH_POWER_OFF;
@@@ -424,9 -396,7 +395,9 @@@ static int i915_load_modeset_init(struc
        if (ret)
                goto cleanup_vga_switcheroo;
  
 -      intel_power_domains_init_hw(dev_priv);
 +      intel_power_domains_init_hw(dev_priv, false);
 +
 +      intel_csr_ucode_init(dev_priv);
  
        ret = intel_irq_install(dev_priv);
        if (ret)
         * working irqs for e.g. gmbus and dp aux transfers. */
        intel_modeset_init(dev);
  
-       /* intel_guc_ucode_init() needs the mutex to allocate GEM objects */
-       mutex_lock(&dev->struct_mutex);
        intel_guc_ucode_init(dev);
-       mutex_unlock(&dev->struct_mutex);
  
        ret = i915_gem_init(dev);
        if (ret)
         * scanning against hotplug events. Hence do this first and ignore the
         * tiny window where we will loose hotplug notifactions.
         */
 -      async_schedule(intel_fbdev_initial_config, dev_priv);
 +      intel_fbdev_initial_config_async(dev);
  
        drm_kms_helper_poll_init(dev);
  
@@@ -482,9 -449,7 +450,7 @@@ cleanup_gem
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
  cleanup_irq:
-       mutex_lock(&dev->struct_mutex);
        intel_guc_ucode_fini(dev);
-       mutex_unlock(&dev->struct_mutex);
        drm_irq_uninstall(dev);
  cleanup_gem_stolen:
        i915_gem_cleanup_stolen(dev);
@@@ -698,8 -663,7 +664,8 @@@ static void gen9_sseu_info_init(struct 
         * supports EU power gating on devices with more than one EU
         * pair per subslice.
        */
 -      info->has_slice_pg = (IS_SKYLAKE(dev) && (info->slice_total > 1));
 +      info->has_slice_pg = ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) &&
 +                             (info->slice_total > 1));
        info->has_subslice_pg = (IS_BROXTON(dev) && (info->subslice_total > 1));
        info->has_eu_pg = (info->eu_per_subslice > 2);
  }
@@@ -926,6 -890,7 +892,6 @@@ int i915_driver_load(struct drm_device 
        spin_lock_init(&dev_priv->mmio_flip_lock);
        mutex_init(&dev_priv->sb_lock);
        mutex_init(&dev_priv->modeset_restore_lock);
 -      mutex_init(&dev_priv->csr_lock);
        mutex_init(&dev_priv->av_mutex);
  
        intel_pm_setup(dev);
  
        intel_uncore_init(dev);
  
 -      /* Load CSR Firmware for SKL */
 -      intel_csr_ucode_init(dev);
 -
        ret = i915_gem_gtt_init(dev);
        if (ret)
                goto out_freecsr;
@@@ -1145,7 -1113,7 +1111,7 @@@ out_mtrrfree
  out_gtt:
        i915_global_gtt_cleanup(dev);
  out_freecsr:
 -      intel_csr_ucode_fini(dev);
 +      intel_csr_ucode_fini(dev_priv);
        intel_uncore_fini(dev);
        pci_iounmap(dev->pdev, dev_priv->regs);
  put_bridge:
@@@ -1163,8 -1131,6 +1129,8 @@@ int i915_driver_unload(struct drm_devic
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
  
 +      intel_fbdev_fini(dev);
 +
        i915_audio_component_cleanup(dev_priv);
  
        ret = i915_gem_suspend(dev);
  
        acpi_video_unregister();
  
 -      intel_fbdev_fini(dev);
 -
        drm_vblank_cleanup(dev);
  
        intel_modeset_cleanup(dev);
        /* Flush any outstanding unpin_work. */
        flush_workqueue(dev_priv->wq);
  
-       mutex_lock(&dev->struct_mutex);
        intel_guc_ucode_fini(dev);
+       mutex_lock(&dev->struct_mutex);
        i915_gem_cleanup_ringbuffer(dev);
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
        intel_fbc_cleanup_cfb(dev_priv);
        i915_gem_cleanup_stolen(dev);
  
 -      intel_csr_ucode_fini(dev);
 +      intel_csr_ucode_fini(dev_priv);
  
        intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
@@@ -1296,6 -1264,8 +1262,6 @@@ void i915_driver_postclose(struct drm_d
  {
        struct drm_i915_file_private *file_priv = file->driver_priv;
  
 -      if (file_priv && file_priv->bsd_ring)
 -              file_priv->bsd_ring = NULL;
        kfree(file_priv);
  }
  
@@@ -1314,7 -1284,7 +1280,7 @@@ const struct drm_ioctl_desc i915_ioctls
        DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, drm_noop, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, drm_noop, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_SETPARAM, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE,  drm_noop, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH),
        DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
+       DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW),
  };
  
  int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
@@@ -57,7 -57,7 +57,7 @@@
  
  #define DRIVER_NAME           "i915"
  #define DRIVER_DESC           "Intel Graphics"
 -#define DRIVER_DATE           "20151010"
 +#define DRIVER_DATE           "20151120"
  
  #undef WARN_ON
  /* Many gcc seem to no see through this and fall over :( */
@@@ -180,11 -180,15 +180,11 @@@ enum intel_display_power_domain 
        POWER_DOMAIN_TRANSCODER_B,
        POWER_DOMAIN_TRANSCODER_C,
        POWER_DOMAIN_TRANSCODER_EDP,
 -      POWER_DOMAIN_PORT_DDI_A_2_LANES,
 -      POWER_DOMAIN_PORT_DDI_A_4_LANES,
 -      POWER_DOMAIN_PORT_DDI_B_2_LANES,
 -      POWER_DOMAIN_PORT_DDI_B_4_LANES,
 -      POWER_DOMAIN_PORT_DDI_C_2_LANES,
 -      POWER_DOMAIN_PORT_DDI_C_4_LANES,
 -      POWER_DOMAIN_PORT_DDI_D_2_LANES,
 -      POWER_DOMAIN_PORT_DDI_D_4_LANES,
 -      POWER_DOMAIN_PORT_DDI_E_2_LANES,
 +      POWER_DOMAIN_PORT_DDI_A_LANES,
 +      POWER_DOMAIN_PORT_DDI_B_LANES,
 +      POWER_DOMAIN_PORT_DDI_C_LANES,
 +      POWER_DOMAIN_PORT_DDI_D_LANES,
 +      POWER_DOMAIN_PORT_DDI_E_LANES,
        POWER_DOMAIN_PORT_DSI,
        POWER_DOMAIN_PORT_CRT,
        POWER_DOMAIN_PORT_OTHER,
        POWER_DOMAIN_AUX_B,
        POWER_DOMAIN_AUX_C,
        POWER_DOMAIN_AUX_D,
 +      POWER_DOMAIN_GMBUS,
 +      POWER_DOMAIN_MODESET,
        POWER_DOMAIN_INIT,
  
        POWER_DOMAIN_NUM,
@@@ -349,6 -351,8 +349,8 @@@ enum intel_dpll_id 
        /* hsw/bdw */
        DPLL_ID_WRPLL1 = 0,
        DPLL_ID_WRPLL2 = 1,
+       DPLL_ID_SPLL = 2,
        /* skl */
        DPLL_ID_SKL_DPLL1 = 0,
        DPLL_ID_SKL_DPLL2 = 1,
@@@ -365,6 -369,7 +367,7 @@@ struct intel_dpll_hw_state 
  
        /* hsw, bdw */
        uint32_t wrpll;
+       uint32_t spll;
  
        /* skl */
        /*
@@@ -625,9 -630,11 +628,9 @@@ struct drm_i915_display_funcs 
                          int target, int refclk,
                          struct dpll *match_clock,
                          struct dpll *best_clock);
 +      int (*compute_pipe_wm)(struct intel_crtc *crtc,
 +                             struct drm_atomic_state *state);
        void (*update_wm)(struct drm_crtc *crtc);
 -      void (*update_sprite_wm)(struct drm_plane *plane,
 -                               struct drm_crtc *crtc,
 -                               uint32_t sprite_width, uint32_t sprite_height,
 -                               int pixel_size, bool enable, bool scaled);
        int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
        void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
        /* Returns the active state of the crtc, and if the crtc is active,
@@@ -685,18 -692,18 +688,18 @@@ struct intel_uncore_funcs 
        void (*force_wake_put)(struct drm_i915_private *dev_priv,
                                                        enum forcewake_domains domains);
  
 -      uint8_t  (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
 -      uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
 -      uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
 -      uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
 +      uint8_t  (*mmio_readb)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
 +      uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
 +      uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
 +      uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace);
  
 -      void (*mmio_writeb)(struct drm_i915_private *dev_priv, off_t offset,
 +      void (*mmio_writeb)(struct drm_i915_private *dev_priv, i915_reg_t r,
                                uint8_t val, bool trace);
 -      void (*mmio_writew)(struct drm_i915_private *dev_priv, off_t offset,
 +      void (*mmio_writew)(struct drm_i915_private *dev_priv, i915_reg_t r,
                                uint16_t val, bool trace);
 -      void (*mmio_writel)(struct drm_i915_private *dev_priv, off_t offset,
 +      void (*mmio_writel)(struct drm_i915_private *dev_priv, i915_reg_t r,
                                uint32_t val, bool trace);
 -      void (*mmio_writeq)(struct drm_i915_private *dev_priv, off_t offset,
 +      void (*mmio_writeq)(struct drm_i915_private *dev_priv, i915_reg_t r,
                                uint64_t val, bool trace);
  };
  
@@@ -713,11 -720,11 +716,11 @@@ struct intel_uncore 
                enum forcewake_domain_id id;
                unsigned wake_count;
                struct timer_list timer;
 -              u32 reg_set;
 +              i915_reg_t reg_set;
                u32 val_set;
                u32 val_clear;
 -              u32 reg_ack;
 -              u32 reg_post;
 +              i915_reg_t reg_ack;
 +              i915_reg_t reg_post;
                u32 val_reset;
        } fw_domain[FW_DOMAIN_ID_COUNT];
  };
  #define for_each_fw_domain(domain__, dev_priv__, i__) \
        for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
  
 -enum csr_state {
 -      FW_UNINITIALIZED = 0,
 -      FW_LOADED,
 -      FW_FAILED
 -};
 +#define CSR_VERSION(major, minor)     ((major) << 16 | (minor))
 +#define CSR_VERSION_MAJOR(version)    ((version) >> 16)
 +#define CSR_VERSION_MINOR(version)    ((version) & 0xffff)
  
  struct intel_csr {
 +      struct work_struct work;
        const char *fw_path;
        uint32_t *dmc_payload;
        uint32_t dmc_fw_size;
 +      uint32_t version;
        uint32_t mmio_count;
 -      uint32_t mmioaddr[8];
 +      i915_reg_t mmioaddr[8];
        uint32_t mmiodata[8];
 -      enum csr_state state;
  };
  
  #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
        func(is_valleyview) sep \
        func(is_haswell) sep \
        func(is_skylake) sep \
 +      func(is_broxton) sep \
 +      func(is_kabylake) sep \
        func(is_preliminary) sep \
        func(has_fbc) sep \
        func(has_pipe_cxsr) sep \
@@@ -922,7 -928,24 +925,7 @@@ struct i915_fbc 
                struct drm_framebuffer *fb;
        } *fbc_work;
  
 -      enum no_fbc_reason {
 -              FBC_OK, /* FBC is enabled */
 -              FBC_UNSUPPORTED, /* FBC is not supported by this chipset */
 -              FBC_NO_OUTPUT, /* no outputs enabled to compress */
 -              FBC_STOLEN_TOO_SMALL, /* not enough space for buffers */
 -              FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
 -              FBC_MODE_TOO_LARGE, /* mode too large for compression */
 -              FBC_BAD_PLANE, /* fbc not supported on plane */
 -              FBC_NOT_TILED, /* buffer not tiled */
 -              FBC_MULTIPLE_PIPES, /* more than one pipe active */
 -              FBC_MODULE_PARAM,
 -              FBC_CHIP_DEFAULT, /* disabled by default on this chip */
 -              FBC_ROTATION, /* rotation is not supported */
 -              FBC_IN_DBG_MASTER, /* kernel debugger is active */
 -              FBC_BAD_STRIDE, /* stride is not supported */
 -              FBC_PIXEL_RATE, /* pixel rate is too big */
 -              FBC_PIXEL_FORMAT /* pixel format is invalid */
 -      } no_fbc_reason;
 +      const char *no_fbc_reason;
  
        bool (*fbc_enabled)(struct drm_i915_private *dev_priv);
        void (*enable_fbc)(struct intel_crtc *crtc);
@@@ -996,7 -1019,7 +999,7 @@@ struct intel_gmbus 
        struct i2c_adapter adapter;
        u32 force_bit;
        u32 reg0;
 -      u32 gpio_reg;
 +      i915_reg_t gpio_reg;
        struct i2c_algo_bit_data bit_algo;
        struct drm_i915_private *dev_priv;
  };
@@@ -1645,7 -1668,7 +1648,7 @@@ struct i915_frontbuffer_tracking 
  };
  
  struct i915_wa_reg {
 -      u32 addr;
 +      i915_reg_t addr;
        u32 value;
        /* bitmask representing WA bits */
        u32 mask;
@@@ -1674,13 -1697,6 +1677,13 @@@ struct i915_execbuffer_params 
        struct drm_i915_gem_request     *request;
  };
  
 +/* used in computing the new watermarks state */
 +struct intel_wm_config {
 +      unsigned int num_pipes_active;
 +      bool sprites_enabled;
 +      bool sprites_scaled;
 +};
 +
  struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *objects;
  
        struct intel_csr csr;
  
 -      /* Display CSR-related protection */
 -      struct mutex csr_lock;
 -
        struct intel_gmbus gmbus[GMBUS_NUM_PINS];
  
        /** gmbus_mutex protects against concurrent usage of the single hw gmbus
        /* MMIO base address for MIPI regs */
        uint32_t mipi_mmio_base;
  
 +      uint32_t psr_mmio_base;
 +
        wait_queue_head_t gmbus_wait_queue;
  
        struct pci_dev *bridge_dev;
        struct mutex pps_mutex;
  
        struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
-       int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
        int num_fence_regs; /* 8 on pre-965, 16 otherwise */
  
        unsigned int fsb_freq, mem_freq, is_ddr3;
                 */
                uint16_t skl_latency[8];
  
 +              /* Committed wm config */
 +              struct intel_wm_config config;
 +
                /*
                 * The skl_wm_values structure is a bit too big for stack
                 * allocation, so we keep the staging struct where we store
@@@ -2422,15 -2435,6 +2424,15 @@@ struct drm_i915_cmd_table 
  #define INTEL_DEVID(p)        (INTEL_INFO(p)->device_id)
  #define INTEL_REVID(p)        (__I915__(p)->dev->pdev->revision)
  
 +#define REVID_FOREVER         0xff
 +/*
 + * Return true if revision is in range [since,until] inclusive.
 + *
 + * Use 0 for open-ended since, and REVID_FOREVER for open-ended until.
 + */
 +#define IS_REVID(p, since, until) \
 +      (INTEL_REVID(p) >= (since) && INTEL_REVID(p) <= (until))
 +
  #define IS_I830(dev)          (INTEL_DEVID(dev) == 0x3577)
  #define IS_845G(dev)          (INTEL_DEVID(dev) == 0x2562)
  #define IS_I85X(dev)          (INTEL_INFO(dev)->is_i85x)
  #define IS_HASWELL(dev)       (INTEL_INFO(dev)->is_haswell)
  #define IS_BROADWELL(dev)     (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
  #define IS_SKYLAKE(dev)       (INTEL_INFO(dev)->is_skylake)
 -#define IS_BROXTON(dev)       (!INTEL_INFO(dev)->is_skylake && IS_GEN9(dev))
 +#define IS_BROXTON(dev)               (INTEL_INFO(dev)->is_broxton)
 +#define IS_KABYLAKE(dev)      (INTEL_INFO(dev)->is_kabylake)
  #define IS_MOBILE(dev)                (INTEL_INFO(dev)->is_mobile)
  #define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \
                                 (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
  
  #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
  
 -#define SKL_REVID_A0          (0x0)
 -#define SKL_REVID_B0          (0x1)
 -#define SKL_REVID_C0          (0x2)
 -#define SKL_REVID_D0          (0x3)
 -#define SKL_REVID_E0          (0x4)
 -#define SKL_REVID_F0          (0x5)
 +#define SKL_REVID_A0          0x0
 +#define SKL_REVID_B0          0x1
 +#define SKL_REVID_C0          0x2
 +#define SKL_REVID_D0          0x3
 +#define SKL_REVID_E0          0x4
 +#define SKL_REVID_F0          0x5
 +
 +#define IS_SKL_REVID(p, since, until) (IS_SKYLAKE(p) && IS_REVID(p, since, until))
 +
 +#define BXT_REVID_A0          0x0
 +#define BXT_REVID_A1          0x1
 +#define BXT_REVID_B0          0x3
 +#define BXT_REVID_C0          0x9
  
 -#define BXT_REVID_A0          (0x0)
 -#define BXT_REVID_B0          (0x3)
 -#define BXT_REVID_C0          (0x9)
 +#define IS_BXT_REVID(p, since, until) (IS_BROXTON(p) && IS_REVID(p, since, until))
  
  /*
   * The genX designation typically refers to the render engine, so render
  #define HAS_FPGA_DBG_UNCLAIMED(dev)   (INTEL_INFO(dev)->has_fpga_dbg)
  #define HAS_PSR(dev)          (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
                                 IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
 -                               IS_SKYLAKE(dev))
 +                               IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
  #define HAS_RUNTIME_PM(dev)   (IS_GEN6(dev) || IS_HASWELL(dev) || \
                                 IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \
 -                               IS_SKYLAKE(dev))
 +                               IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
  #define HAS_RC6(dev)          (INTEL_INFO(dev)->gen >= 6)
  #define HAS_RC6p(dev)         (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
  
@@@ -2642,7 -2640,6 +2644,7 @@@ struct i915_params 
        int panel_use_ssc;
        int vbt_sdvo_panel_type;
        int enable_rc6;
 +      int enable_dc;
        int enable_fbc;
        int enable_ppgtt;
        int enable_execlists;
        int enable_cmd_parser;
        /* leave bools at the end to not create holes */
        bool enable_hangcheck;
+       bool fastboot;
        bool prefault_disable;
        bool load_detect_test;
        bool reset;
@@@ -2690,6 -2688,7 +2693,6 @@@ extern unsigned long i915_mch_val(struc
  extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
  extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
  int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
 -void i915_firmware_load_error_print(const char *fw_path, int err);
  
  /* intel_hotplug.c */
  void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask);
@@@ -2996,6 -2995,8 +2999,6 @@@ i915_gem_object_set_to_cpu_domain(struc
  int __must_check
  i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
 -                                   struct intel_engine_cs *pipelined,
 -                                   struct drm_i915_gem_request **pipelined_request,
                                     const struct i915_ggtt_view *view);
  void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
                                              const struct i915_ggtt_view *view);
@@@ -3350,6 -3351,7 +3353,6 @@@ extern void intel_set_rps(struct drm_de
  extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
                                  bool enable);
  extern void intel_detect_pch(struct drm_device *dev);
 -extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
  extern int intel_enable_rc6(const struct drm_device *dev);
  
  extern bool i915_semaphore_is_enabled(struct drm_device *dev);
@@@ -3432,32 -3434,6 +3435,32 @@@ int intel_freq_opcode(struct drm_i915_p
  #define POSTING_READ(reg)     (void)I915_READ_NOTRACE(reg)
  #define POSTING_READ16(reg)   (void)I915_READ16_NOTRACE(reg)
  
 +#define __raw_read(x, s) \
 +static inline uint##x##_t __raw_i915_read##x(struct drm_i915_private *dev_priv, \
 +                                           i915_reg_t reg) \
 +{ \
 +      return read##s(dev_priv->regs + i915_mmio_reg_offset(reg)); \
 +}
 +
 +#define __raw_write(x, s) \
 +static inline void __raw_i915_write##x(struct drm_i915_private *dev_priv, \
 +                                     i915_reg_t reg, uint##x##_t val) \
 +{ \
 +      write##s(val, dev_priv->regs + i915_mmio_reg_offset(reg)); \
 +}
 +__raw_read(8, b)
 +__raw_read(16, w)
 +__raw_read(32, l)
 +__raw_read(64, q)
 +
 +__raw_write(8, b)
 +__raw_write(16, w)
 +__raw_write(32, l)
 +__raw_write(64, q)
 +
 +#undef __raw_read
 +#undef __raw_write
 +
  /* These are untraced mmio-accessors that are only valid to be used inside
   * criticial sections inside IRQ handlers where forcewake is explicitly
   * controlled.
   * Note: Should only be used between intel_uncore_forcewake_irqlock() and
   * intel_uncore_forcewake_irqunlock().
   */
 -#define I915_READ_FW(reg__) readl(dev_priv->regs + (reg__))
 -#define I915_WRITE_FW(reg__, val__) writel(val__, dev_priv->regs + (reg__))
 +#define I915_READ_FW(reg__) __raw_i915_read32(dev_priv, (reg__))
 +#define I915_WRITE_FW(reg__, val__) __raw_i915_write32(dev_priv, (reg__), (val__))
  #define POSTING_READ_FW(reg__) (void)I915_READ_FW(reg__)
  
  /* "Broadcast RGB" property */
  #define INTEL_BROADCAST_RGB_FULL 1
  #define INTEL_BROADCAST_RGB_LIMITED 2
  
 -static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev)
 +static inline i915_reg_t i915_vgacntrl_reg(struct drm_device *dev)
  {
        if (IS_VALLEYVIEW(dev))
                return VLV_VGACNTRL;
@@@ -2216,9 -2216,8 +2216,8 @@@ i915_gem_object_get_pages_gtt(struct dr
         * Fail silently without starting the shrinker
         */
        mapping = file_inode(obj->base.filp)->i_mapping;
-       gfp = mapping_gfp_mask(mapping);
-       gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
-       gfp &= ~(__GFP_IO | __GFP_WAIT);
+       gfp = mapping_gfp_constraint(mapping, ~(__GFP_IO | __GFP_RECLAIM));
+       gfp |= __GFP_NORETRY | __GFP_NOWARN;
        sg = st->sgl;
        st->nents = 0;
        for (i = 0; i < page_count; i++) {
@@@ -2738,8 -2737,6 +2737,8 @@@ static void i915_gem_reset_ring_status(
  static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                                        struct intel_engine_cs *ring)
  {
 +      struct intel_ringbuffer *buffer;
 +
        while (!list_empty(&ring->active_list)) {
                struct drm_i915_gem_object *obj;
  
         * are the ones that keep the context and ringbuffer backing objects
         * pinned in place.
         */
 -      while (!list_empty(&ring->execlist_queue)) {
 -              struct drm_i915_gem_request *submit_req;
  
 -              submit_req = list_first_entry(&ring->execlist_queue,
 -                              struct drm_i915_gem_request,
 -                              execlist_link);
 -              list_del(&submit_req->execlist_link);
 +      if (i915.enable_execlists) {
 +              spin_lock_irq(&ring->execlist_lock);
 +              while (!list_empty(&ring->execlist_queue)) {
 +                      struct drm_i915_gem_request *submit_req;
 +
 +                      submit_req = list_first_entry(&ring->execlist_queue,
 +                                      struct drm_i915_gem_request,
 +                                      execlist_link);
 +                      list_del(&submit_req->execlist_link);
  
 -              if (submit_req->ctx != ring->default_context)
 -                      intel_lr_context_unpin(submit_req);
 +                      if (submit_req->ctx != ring->default_context)
 +                              intel_lr_context_unpin(submit_req);
  
 -              i915_gem_request_unreference(submit_req);
 +                      i915_gem_request_unreference(submit_req);
 +              }
 +              spin_unlock_irq(&ring->execlist_lock);
        }
  
        /*
  
                i915_gem_request_retire(request);
        }
 +
 +      /* Having flushed all requests from all queues, we know that all
 +       * ringbuffers must now be empty. However, since we do not reclaim
 +       * all space when retiring the request (to prevent HEADs colliding
 +       * with rapid ringbuffer wraparound) the amount of available space
 +       * upon reset is less than when we start. Do one more pass over
 +       * all the ringbuffers to reset last_retired_head.
 +       */
 +      list_for_each_entry(buffer, &ring->buffers, link) {
 +              buffer->last_retired_head = buffer->tail;
 +              intel_ring_update_space(buffer);
 +      }
  }
  
  void i915_gem_reset(struct drm_device *dev)
@@@ -3829,6 -3809,7 +3828,7 @@@ int i915_gem_get_caching_ioctl(struct d
  int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
                               struct drm_file *file)
  {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_caching *args = data;
        struct drm_i915_gem_object *obj;
        enum i915_cache_level level;
                 * cacheline, whereas normally such cachelines would get
                 * invalidated.
                 */
 -              if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)
 +              if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                        return -ENODEV;
  
                level = I915_CACHE_LLC;
                return -EINVAL;
        }
  
+       intel_runtime_pm_get(dev_priv);
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
-               return ret;
+               goto rpm_put;
  
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
        if (&obj->base == NULL) {
        drm_gem_object_unreference(&obj->base);
  unlock:
        mutex_unlock(&dev->struct_mutex);
+ rpm_put:
+       intel_runtime_pm_put(dev_priv);
        return ret;
  }
  
  int
  i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
                                     u32 alignment,
 -                                   struct intel_engine_cs *pipelined,
 -                                   struct drm_i915_gem_request **pipelined_request,
                                     const struct i915_ggtt_view *view)
  {
        u32 old_read_domains, old_write_domain;
        int ret;
  
 -      ret = i915_gem_object_sync(obj, pipelined, pipelined_request);
 -      if (ret)
 -              return ret;
 -
        /* Mark the pin_display early so that we account for the
         * display coherency whilst setting up the cache domains.
         */
@@@ -4484,8 -4476,10 +4489,8 @@@ struct i915_vma *i915_gem_obj_to_vma(st
  {
        struct i915_vma *vma;
        list_for_each_entry(vma, &obj->vma_list, vma_link) {
 -              if (i915_is_ggtt(vma->vm) &&
 -                  vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL)
 -                      continue;
 -              if (vma->vm == vm)
 +              if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL &&
 +                  vma->vm == vm)
                        return vma;
        }
        return NULL;
@@@ -4574,6 -4568,7 +4579,6 @@@ int i915_gem_l3_remap(struct drm_i915_g
        struct intel_engine_cs *ring = req->ring;
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200);
        u32 *remap_info = dev_priv->l3_parity.remap_info[slice];
        int i, ret;
  
         * here because no other code should access these registers other than
         * at initialization time.
         */
 -      for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) {
 +      for (i = 0; i < GEN7_L3LOG_SIZE / 4; i++) {
                intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
 -              intel_ring_emit(ring, reg_base + i);
 -              intel_ring_emit(ring, remap_info[i/4]);
 +              intel_ring_emit_reg(ring, GEN7_L3LOG(slice, i));
 +              intel_ring_emit(ring, remap_info[i]);
        }
  
        intel_ring_advance(ring);
@@@ -4760,9 -4755,18 +4765,9 @@@ i915_gem_init_hw(struct drm_device *dev
        if (HAS_GUC_UCODE(dev)) {
                ret = intel_guc_ucode_load(dev);
                if (ret) {
 -                      /*
 -                       * If we got an error and GuC submission is enabled, map
 -                       * the error to -EIO so the GPU will be declared wedged.
 -                       * OTOH, if we didn't intend to use the GuC anyway, just
 -                       * discard the error and carry on.
 -                       */
 -                      DRM_ERROR("Failed to initialize GuC, error %d%s\n", ret,
 -                                i915.enable_guc_submission ? "" :
 -                                " (ignored)");
 -                      ret = i915.enable_guc_submission ? -EIO : 0;
 -                      if (ret)
 -                              goto out;
 +                      DRM_ERROR("Failed to initialize GuC, error %d\n", ret);
 +                      ret = -EIO;
 +                      goto out;
                }
        }
  
@@@ -59,7 -59,7 +59,7 @@@ static void i965_write_fence_reg(struc
                                 struct drm_i915_gem_object *obj)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      int fence_reg_lo, fence_reg_hi;
 +      i915_reg_t fence_reg_lo, fence_reg_hi;
        int fence_pitch_shift;
  
        if (INTEL_INFO(dev)->gen >= 6) {
@@@ -317,7 -317,7 +317,7 @@@ i915_find_fence_reg(struct drm_device *
  
        /* First try to find a free reg */
        avail = NULL;
-       for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
+       for (i = 0; i < dev_priv->num_fence_regs; i++) {
                reg = &dev_priv->fence_regs[i];
                if (!reg->obj)
                        return reg;
@@@ -139,8 -139,7 +139,8 @@@ static const u32 hpd_bxt[HPD_NUM_PINS] 
  /*
   * We should clear IMR at preinstall/uninstall, and just check at postinstall.
   */
 -static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg)
 +static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
 +                                  i915_reg_t reg)
  {
        u32 val = I915_READ(reg);
  
                return;
  
        WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
 -           reg, val);
 +           i915_mmio_reg_offset(reg), val);
        I915_WRITE(reg, 0xffffffff);
        POSTING_READ(reg);
        I915_WRITE(reg, 0xffffffff);
@@@ -284,17 -283,17 +284,17 @@@ void gen5_disable_gt_irq(struct drm_i91
        ilk_update_gt_irq(dev_priv, mask, 0);
  }
  
 -static u32 gen6_pm_iir(struct drm_i915_private *dev_priv)
 +static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
  {
        return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
  }
  
 -static u32 gen6_pm_imr(struct drm_i915_private *dev_priv)
 +static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
  {
        return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR;
  }
  
 -static u32 gen6_pm_ier(struct drm_i915_private *dev_priv)
 +static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
  {
        return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER;
  }
@@@ -351,7 -350,7 +351,7 @@@ void gen6_disable_pm_irq(struct drm_i91
  void gen6_reset_rps_interrupts(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      uint32_t reg = gen6_pm_iir(dev_priv);
 +      i915_reg_t reg = gen6_pm_iir(dev_priv);
  
        spin_lock_irq(&dev_priv->irq_lock);
        I915_WRITE(reg, dev_priv->pm_rps_events);
@@@ -478,7 -477,7 +478,7 @@@ static voi
  __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
                       u32 enable_mask, u32 status_mask)
  {
 -      u32 reg = PIPESTAT(pipe);
 +      i915_reg_t reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
  
        assert_spin_locked(&dev_priv->irq_lock);
@@@ -505,7 -504,7 +505,7 @@@ static voi
  __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
                        u32 enable_mask, u32 status_mask)
  {
 -      u32 reg = PIPESTAT(pipe);
 +      i915_reg_t reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
  
        assert_spin_locked(&dev_priv->irq_lock);
@@@ -654,7 -653,7 +654,7 @@@ static void i915_enable_asle_pipestat(s
   *   of horizontal active on the first line of vertical active
   */
  
- static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
+ static u32 i8xx_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
  {
        /* Gen2 doesn't have a hardware frame counter */
        return 0;
  /* Called from drm generic code, passed a 'crtc', which
   * we use as a pipe index
   */
- static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
+ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      unsigned long high_frame;
 -      unsigned long low_frame;
 +      i915_reg_t high_frame, low_frame;
        u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
        return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
  }
  
- static u32 g4x_get_vblank_counter(struct drm_device *dev, int pipe)
+ static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
  }
  
 -/* raw reads, only for fast reads of display block, no need for forcewake etc. */
 -#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
 -
 +/* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */
  static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
  {
        struct drm_device *dev = crtc->base.dev;
                vtotal /= 2;
  
        if (IS_GEN2(dev))
 -              position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
 +              position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
        else
 -              position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 +              position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
  
        /*
         * On HSW, the DSL reg (0x70000) appears to return 0 if we
         * problem.  We may need to extend this to include other platforms,
         * but so far testing only shows the problem on HSW.
         */
-       if (IS_HASWELL(dev) && !position) {
+       if (HAS_DDI(dev) && !position) {
                int i, temp;
  
                for (i = 0; i < 100; i++) {
        return (position + crtc->scanline_offset) % vtotal;
  }
  
- static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
+ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
                                    unsigned int flags, int *vpos, int *hpos,
                                    ktime_t *stime, ktime_t *etime,
                                    const struct drm_display_mode *mode)
                 * We can split this into vertical and horizontal
                 * scanout position.
                 */
 -              position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
 +              position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
  
                /* convert to pixel counts */
                vbl_start *= htotal;
@@@ -905,27 -907,27 +905,27 @@@ int intel_get_crtc_scanline(struct inte
        return position;
  }
  
- static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
+ static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
                              int *max_error,
                              struct timeval *vblank_time,
                              unsigned flags)
  {
        struct drm_crtc *crtc;
  
-       if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) {
-               DRM_ERROR("Invalid crtc %d\n", pipe);
+       if (pipe >= INTEL_INFO(dev)->num_pipes) {
+               DRM_ERROR("Invalid crtc %u\n", pipe);
                return -EINVAL;
        }
  
        /* Get drm_crtc to timestamp: */
        crtc = intel_get_crtc_for_pipe(dev, pipe);
        if (crtc == NULL) {
-               DRM_ERROR("Invalid crtc %d\n", pipe);
+               DRM_ERROR("Invalid crtc %u\n", pipe);
                return -EINVAL;
        }
  
        if (!crtc->hwmode.crtc_clock) {
-               DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+               DRM_DEBUG_KMS("crtc %u is disabled\n", pipe);
                return -EBUSY;
        }
  
@@@ -1186,7 -1188,7 +1186,7 @@@ static void ivybridge_parity_work(struc
        POSTING_READ(GEN7_MISCCPCTL);
  
        while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
 -              u32 reg;
 +              i915_reg_t reg;
  
                slice--;
                if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
  
                dev_priv->l3_parity.which_slice &= ~(1<<slice);
  
 -              reg = GEN7_L3CDERRST1 + (slice * 0x200);
 +              reg = GEN7_L3CDERRST1(slice);
  
                error_status = I915_READ(reg);
                row = GEN7_PARITY_ERROR_ROW(error_status);
@@@ -1288,69 -1290,70 +1288,69 @@@ static void snb_gt_irq_handler(struct d
                ivybridge_parity_error_irq_handler(dev, gt_iir);
  }
  
 +static __always_inline void
 +gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift)
 +{
 +      if (iir & (GT_RENDER_USER_INTERRUPT << test_shift))
 +              notify_ring(ring);
 +      if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
 +              intel_lrc_irq_handler(ring);
 +}
 +
  static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
                                       u32 master_ctl)
  {
        irqreturn_t ret = IRQ_NONE;
  
        if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
 -              u32 tmp = I915_READ_FW(GEN8_GT_IIR(0));
 -              if (tmp) {
 -                      I915_WRITE_FW(GEN8_GT_IIR(0), tmp);
 +              u32 iir = I915_READ_FW(GEN8_GT_IIR(0));
 +              if (iir) {
 +                      I915_WRITE_FW(GEN8_GT_IIR(0), iir);
                        ret = IRQ_HANDLED;
  
 -                      if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT))
 -                              intel_lrc_irq_handler(&dev_priv->ring[RCS]);
 -                      if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT))
 -                              notify_ring(&dev_priv->ring[RCS]);
 +                      gen8_cs_irq_handler(&dev_priv->ring[RCS],
 +                                      iir, GEN8_RCS_IRQ_SHIFT);
  
 -                      if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT))
 -                              intel_lrc_irq_handler(&dev_priv->ring[BCS]);
 -                      if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT))
 -                              notify_ring(&dev_priv->ring[BCS]);
 +                      gen8_cs_irq_handler(&dev_priv->ring[BCS],
 +                                      iir, GEN8_BCS_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
  
        if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
 -              u32 tmp = I915_READ_FW(GEN8_GT_IIR(1));
 -              if (tmp) {
 -                      I915_WRITE_FW(GEN8_GT_IIR(1), tmp);
 +              u32 iir = I915_READ_FW(GEN8_GT_IIR(1));
 +              if (iir) {
 +                      I915_WRITE_FW(GEN8_GT_IIR(1), iir);
                        ret = IRQ_HANDLED;
  
 -                      if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT))
 -                              intel_lrc_irq_handler(&dev_priv->ring[VCS]);
 -                      if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT))
 -                              notify_ring(&dev_priv->ring[VCS]);
 +                      gen8_cs_irq_handler(&dev_priv->ring[VCS],
 +                                      iir, GEN8_VCS1_IRQ_SHIFT);
  
 -                      if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))
 -                              intel_lrc_irq_handler(&dev_priv->ring[VCS2]);
 -                      if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT))
 -                              notify_ring(&dev_priv->ring[VCS2]);
 +                      gen8_cs_irq_handler(&dev_priv->ring[VCS2],
 +                                      iir, GEN8_VCS2_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
  
        if (master_ctl & GEN8_GT_VECS_IRQ) {
 -              u32 tmp = I915_READ_FW(GEN8_GT_IIR(3));
 -              if (tmp) {
 -                      I915_WRITE_FW(GEN8_GT_IIR(3), tmp);
 +              u32 iir = I915_READ_FW(GEN8_GT_IIR(3));
 +              if (iir) {
 +                      I915_WRITE_FW(GEN8_GT_IIR(3), iir);
                        ret = IRQ_HANDLED;
  
 -                      if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT))
 -                              intel_lrc_irq_handler(&dev_priv->ring[VECS]);
 -                      if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT))
 -                              notify_ring(&dev_priv->ring[VECS]);
 +                      gen8_cs_irq_handler(&dev_priv->ring[VECS],
 +                                      iir, GEN8_VECS_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
  
        if (master_ctl & GEN8_GT_PM_IRQ) {
 -              u32 tmp = I915_READ_FW(GEN8_GT_IIR(2));
 -              if (tmp & dev_priv->pm_rps_events) {
 +              u32 iir = I915_READ_FW(GEN8_GT_IIR(2));
 +              if (iir & dev_priv->pm_rps_events) {
                        I915_WRITE_FW(GEN8_GT_IIR(2),
 -                                    tmp & dev_priv->pm_rps_events);
 +                                    iir & dev_priv->pm_rps_events);
                        ret = IRQ_HANDLED;
 -                      gen6_rps_irq_handler(dev_priv, tmp);
 +                      gen6_rps_irq_handler(dev_priv, iir);
                } else
                        DRM_ERROR("The master control interrupt lied (PM)!\n");
        }
@@@ -1622,7 -1625,7 +1622,7 @@@ static void valleyview_pipestat_irq_han
  
        spin_lock(&dev_priv->irq_lock);
        for_each_pipe(dev_priv, pipe) {
 -              int reg;
 +              i915_reg_t reg;
                u32 mask, iir_bit = 0;
  
                /*
@@@ -2351,13 -2354,9 +2351,13 @@@ static irqreturn_t gen8_irq_handler(in
                                spt_irq_handler(dev, pch_iir);
                        else
                                cpt_irq_handler(dev, pch_iir);
 -              } else
 -                      DRM_ERROR("The master control interrupt lied (SDE)!\n");
 -
 +              } else {
 +                      /*
 +                       * Like on previous PCH there seems to be something
 +                       * fishy going on with forwarding PCH interrupts.
 +                       */
 +                      DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n");
 +              }
        }
  
        I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
@@@ -2620,7 -2619,7 +2620,7 @@@ void i915_handle_error(struct drm_devic
  /* Called from drm generic code, passed 'crtc' which
   * we use as a pipe index
   */
- static int i915_enable_vblank(struct drm_device *dev, int pipe)
+ static int i915_enable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        return 0;
  }
  
- static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
+ static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        return 0;
  }
  
- static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
+ static int valleyview_enable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        return 0;
  }
  
- static int gen8_enable_vblank(struct drm_device *dev, int pipe)
+ static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
  /* Called from drm generic code, passed 'crtc' which
   * we use as a pipe index
   */
- static void i915_disable_vblank(struct drm_device *dev, int pipe)
+ static void i915_disable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  }
  
- static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
+ static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  }
  
- static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
+ static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  }
  
- static void gen8_disable_vblank(struct drm_device *dev, int pipe)
+ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
@@@ -3870,7 -3869,7 +3870,7 @@@ static irqreturn_t i8xx_irq_handler(in
                        DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
  
                for_each_pipe(dev_priv, pipe) {
 -                      int reg = PIPESTAT(pipe);
 +                      i915_reg_t reg = PIPESTAT(pipe);
                        pipe_stats[pipe] = I915_READ(reg);
  
                        /*
@@@ -4051,7 -4050,7 +4051,7 @@@ static irqreturn_t i915_irq_handler(in
                        DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
  
                for_each_pipe(dev_priv, pipe) {
 -                      int reg = PIPESTAT(pipe);
 +                      i915_reg_t reg = PIPESTAT(pipe);
                        pipe_stats[pipe] = I915_READ(reg);
  
                        /* Clear the PIPE*STAT regs before the IIR */
@@@ -4237,9 -4236,10 +4237,10 @@@ static void i915_hpd_irq_setup(struct d
  
        /* Ignore TV since it's buggy */
        i915_hotplug_interrupt_update_locked(dev_priv,
-                                     (HOTPLUG_INT_EN_MASK
-                                      | CRT_HOTPLUG_VOLTAGE_COMPARE_MASK),
-                                     hotplug_en);
+                                            HOTPLUG_INT_EN_MASK |
+                                            CRT_HOTPLUG_VOLTAGE_COMPARE_MASK |
+                                            CRT_HOTPLUG_ACTIVATION_PERIOD_64,
+                                            hotplug_en);
  }
  
  static irqreturn_t i965_irq_handler(int irq, void *arg)
                        DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
  
                for_each_pipe(dev_priv, pipe) {
 -                      int reg = PIPESTAT(pipe);
 +                      i915_reg_t reg = PIPESTAT(pipe);
                        pipe_stats[pipe] = I915_READ(reg);
  
                        /*
@@@ -32,15 -32,15 +32,16 @@@ struct i915_params i915 __read_mostly 
        .panel_use_ssc = -1,
        .vbt_sdvo_panel_type = -1,
        .enable_rc6 = -1,
 +      .enable_dc = -1,
        .enable_fbc = -1,
        .enable_execlists = -1,
        .enable_hangcheck = true,
        .enable_ppgtt = -1,
        .enable_psr = 0,
        .preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
-       .disable_power_well = 1,
+       .disable_power_well = -1,
        .enable_ips = 1,
+       .fastboot = 0,
        .prefault_disable = 0,
        .load_detect_test = 0,
        .reset = true,
@@@ -80,11 -80,6 +81,11 @@@ MODULE_PARM_DESC(enable_rc6
        "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
        "default: -1 (use per-chip default)");
  
 +module_param_named_unsafe(enable_dc, i915.enable_dc, int, 0400);
 +MODULE_PARM_DESC(enable_dc,
 +      "Enable power-saving display C-states. "
 +      "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6)");
 +
  module_param_named_unsafe(enable_fbc, i915.enable_fbc, int, 0600);
  MODULE_PARM_DESC(enable_fbc,
        "Enable frame buffer compression for power savings "
@@@ -117,7 -112,7 +118,7 @@@ MODULE_PARM_DESC(enable_hangcheck
  module_param_named_unsafe(enable_ppgtt, i915.enable_ppgtt, int, 0400);
  MODULE_PARM_DESC(enable_ppgtt,
        "Override PPGTT usage. "
 -      "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
 +      "(-1=auto [default], 0=disabled, 1=aliasing, 2=full, 3=full with extended address space)");
  
  module_param_named_unsafe(enable_execlists, i915.enable_execlists, int, 0400);
  MODULE_PARM_DESC(enable_execlists,
@@@ -131,13 -126,18 +132,18 @@@ module_param_named_unsafe(preliminary_h
  MODULE_PARM_DESC(preliminary_hw_support,
        "Enable preliminary hardware support.");
  
 -module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0600);
 +module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0400);
  MODULE_PARM_DESC(disable_power_well,
-       "Disable the power well when possible (default: true)");
+       "Disable display power wells when possible "
+       "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)");
  
  module_param_named_unsafe(enable_ips, i915.enable_ips, int, 0600);
  MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
  
+ module_param_named(fastboot, i915.fastboot, bool, 0600);
+ MODULE_PARM_DESC(fastboot,
+       "Try to skip unnecessary mode sets at boot time (default: false)");
  module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600);
  MODULE_PARM_DESC(prefault_disable,
        "Disable page prefaulting for pread/pwrite/reloc (default:false). "
@@@ -61,21 -61,21 +61,21 @@@ static const struct 
        int clock;
        u32 config;
  } hdmi_audio_clock[] = {
-       { DIV_ROUND_UP(25200 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 },
+       { 25175, AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 },
        { 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */
        { 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 },
-       { 27000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 },
+       { 27027, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 },
        { 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 },
-       { 54000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 },
-       { DIV_ROUND_UP(74250 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 },
+       { 54054, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 },
+       { 74176, AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 },
        { 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 },
-       { DIV_ROUND_UP(148500 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 },
+       { 148352, AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 },
        { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 },
  };
  
  /* HDMI N/CTS table */
  #define TMDS_297M 297000
- #define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001)
+ #define TMDS_296M 296703
  static const struct {
        int sample_rate;
        int clock;
@@@ -161,9 -161,9 +161,9 @@@ static bool audio_rate_need_prog(struc
  }
  
  static bool intel_eld_uptodate(struct drm_connector *connector,
 -                             int reg_eldv, uint32_t bits_eldv,
 -                             int reg_elda, uint32_t bits_elda,
 -                             int reg_edid)
 +                             i915_reg_t reg_eldv, uint32_t bits_eldv,
 +                             i915_reg_t reg_elda, uint32_t bits_elda,
 +                             i915_reg_t reg_edid)
  {
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
        uint8_t *eld = connector->eld;
@@@ -364,7 -364,8 +364,7 @@@ static void ilk_audio_codec_disable(str
        enum port port = intel_dig_port->port;
        enum pipe pipe = intel_crtc->pipe;
        uint32_t tmp, eldv;
 -      int aud_config;
 -      int aud_cntrl_st2;
 +      i915_reg_t aud_config, aud_cntrl_st2;
  
        DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n",
                      port_name(port), pipe_name(pipe));
@@@ -415,7 -416,10 +415,7 @@@ static void ilk_audio_codec_enable(stru
        uint32_t eldv;
        uint32_t tmp;
        int len, i;
 -      int hdmiw_hdmiedid;
 -      int aud_config;
 -      int aud_cntl_st;
 -      int aud_cntrl_st2;
 +      i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
  
        DRM_DEBUG_KMS("Enable audio codec on port %c, pipe %c, %u bytes ELD\n",
                      port_name(port), pipe_name(pipe), drm_eld_size(eld));
@@@ -587,7 -591,7 +587,7 @@@ static void i915_audio_component_codec_
        struct drm_i915_private *dev_priv = dev_to_i915(dev);
        u32 tmp;
  
 -      if (!IS_SKYLAKE(dev_priv))
 +      if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv))
                return;
  
        /*
@@@ -638,11 -642,10 +638,11 @@@ static int i915_audio_component_sync_au
        u32 tmp;
        int n;
  
 -      /* HSW, BDW SKL need this fix */
 +      /* HSW, BDW, SKL, KBL need this fix */
        if (!IS_SKYLAKE(dev_priv) &&
 -              !IS_BROADWELL(dev_priv) &&
 -              !IS_HASWELL(dev_priv))
 +          !IS_KABYLAKE(dev_priv) &&
 +          !IS_BROADWELL(dev_priv) &&
 +          !IS_HASWELL(dev_priv))
                return 0;
  
        mutex_lock(&dev_priv->av_mutex);
@@@ -50,7 -50,7 +50,7 @@@ struct intel_crt 
         * encoder's enable/disable callbacks */
        struct intel_connector *connector;
        bool force_hotplug_required;
 -      u32 adpa_reg;
 +      i915_reg_t adpa_reg;
  };
  
  static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
@@@ -138,18 -138,6 +138,6 @@@ static void hsw_crt_get_config(struct i
        pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
  }
  
- static void hsw_crt_pre_enable(struct intel_encoder *encoder)
- {
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL already enabled\n");
-       I915_WRITE(SPLL_CTL,
-                  SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC);
-       POSTING_READ(SPLL_CTL);
-       udelay(20);
- }
  /* Note: The caller is required to filter out dpms modes not supported by the
   * platform. */
  static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@@ -216,19 -204,6 +204,6 @@@ static void pch_post_disable_crt(struc
        intel_disable_crt(encoder);
  }
  
- static void hsw_crt_post_disable(struct intel_encoder *encoder)
- {
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t val;
-       DRM_DEBUG_KMS("Disabling SPLL\n");
-       val = I915_READ(SPLL_CTL);
-       WARN_ON(!(val & SPLL_PLL_ENABLE));
-       I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
-       POSTING_READ(SPLL_CTL);
- }
  static void intel_enable_crt(struct intel_encoder *encoder)
  {
        struct intel_crt *crt = intel_encoder_to_crt(encoder);
@@@ -280,6 -255,10 +255,10 @@@ static bool intel_crt_compute_config(st
        if (HAS_DDI(dev)) {
                pipe_config->ddi_pll_sel = PORT_CLK_SEL_SPLL;
                pipe_config->port_clock = 135000 * 2;
+               pipe_config->dpll_hw_state.wrpll = 0;
+               pipe_config->dpll_hw_state.spll =
+                       SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
        }
  
        return true;
@@@ -501,8 -480,12 +480,8 @@@ intel_crt_load_detect(struct intel_crt 
        uint32_t vsample;
        uint32_t vblank, vblank_start, vblank_end;
        uint32_t dsl;
 -      uint32_t bclrpat_reg;
 -      uint32_t vtotal_reg;
 -      uint32_t vblank_reg;
 -      uint32_t vsync_reg;
 -      uint32_t pipeconf_reg;
 -      uint32_t pipe_dsl_reg;
 +      i915_reg_t bclrpat_reg, vtotal_reg,
 +              vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg;
        uint8_t st00;
        enum drm_connector_status status;
  
                /* Wait for next Vblank to substitue
                 * border color for Color info */
                intel_wait_for_vblank(dev, pipe);
 -              st00 = I915_READ8(VGA_MSR_WRITE);
 +              st00 = I915_READ8(_VGA_MSR_WRITE);
                status = ((st00 & (1 << 4)) != 0) ?
                        connector_status_connected :
                        connector_status_disconnected;
                do {
                        count++;
                        /* Read the ST00 VGA status register */
 -                      st00 = I915_READ8(VGA_MSR_WRITE);
 +                      st00 = I915_READ8(_VGA_MSR_WRITE);
                        if (st00 & (1 << 4))
                                detect++;
                } while ((I915_READ(pipe_dsl_reg) == dsl));
@@@ -856,8 -839,6 +835,6 @@@ void intel_crt_init(struct drm_device *
        if (HAS_DDI(dev)) {
                crt->base.get_config = hsw_crt_get_config;
                crt->base.get_hw_state = intel_ddi_get_hw_state;
-               crt->base.pre_enable = hsw_crt_pre_enable;
-               crt->base.post_disable = hsw_crt_post_disable;
        } else {
                crt->base.get_config = intel_crt_get_config;
                crt->base.get_hw_state = intel_crt_get_hw_state;
@@@ -133,12 -133,12 +133,12 @@@ static const struct ddi_buf_trans skl_d
        { 0x00002016, 0x000000A0, 0x0 },
        { 0x00005012, 0x0000009B, 0x0 },
        { 0x00007011, 0x00000088, 0x0 },
 -      { 0x00009010, 0x000000C7, 0x0 },
 +      { 0x80009010, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
        { 0x00002016, 0x0000009B, 0x0 },
        { 0x00005012, 0x00000088, 0x0 },
 -      { 0x00007011, 0x000000C7, 0x0 },
 +      { 0x80007011, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
        { 0x00002016, 0x000000DF, 0x0 },
 -      { 0x00005012, 0x000000C7, 0x0 },
 +      { 0x80005012, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
  };
  
  /* Skylake U */
@@@ -146,12 -146,12 +146,12 @@@ static const struct ddi_buf_trans skl_u
        { 0x0000201B, 0x000000A2, 0x0 },
        { 0x00005012, 0x00000088, 0x0 },
        { 0x00007011, 0x00000087, 0x0 },
 -      { 0x80009010, 0x000000C7, 0x1 },        /* Uses I_boost level 0x1 */
 +      { 0x80009010, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
        { 0x0000201B, 0x0000009D, 0x0 },
 -      { 0x00005012, 0x000000C7, 0x0 },
 -      { 0x00007011, 0x000000C7, 0x0 },
 +      { 0x80005012, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
 +      { 0x80007011, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
        { 0x00002016, 0x00000088, 0x0 },
 -      { 0x00005012, 0x000000C7, 0x0 },
 +      { 0x80005012, 0x000000C0, 0x1 },        /* Uses I_boost level 0x1 */
  };
  
  /* Skylake Y */
@@@ -159,12 -159,12 +159,12 @@@ static const struct ddi_buf_trans skl_y
        { 0x00000018, 0x000000A2, 0x0 },
        { 0x00005012, 0x00000088, 0x0 },
        { 0x00007011, 0x00000087, 0x0 },
 -      { 0x80009010, 0x000000C7, 0x3 },        /* Uses I_boost level 0x3 */
 +      { 0x80009010, 0x000000C0, 0x3 },        /* Uses I_boost level 0x3 */
        { 0x00000018, 0x0000009D, 0x0 },
 -      { 0x00005012, 0x000000C7, 0x0 },
 -      { 0x00007011, 0x000000C7, 0x0 },
 +      { 0x80005012, 0x000000C0, 0x3 },        /* Uses I_boost level 0x3 */
 +      { 0x80007011, 0x000000C0, 0x3 },        /* Uses I_boost level 0x3 */
        { 0x00000018, 0x00000088, 0x0 },
 -      { 0x00005012, 0x000000C7, 0x0 },
 +      { 0x80005012, 0x000000C0, 0x3 },        /* Uses I_boost level 0x3 */
  };
  
  /*
@@@ -345,7 -345,7 +345,7 @@@ enum port intel_ddi_get_encoder_port(st
  static bool
  intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port)
  {
 -      return intel_dig_port->hdmi.hdmi_reg;
 +      return i915_mmio_reg_valid(intel_dig_port->hdmi.hdmi_reg);
  }
  
  static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev,
@@@ -448,7 -448,7 +448,7 @@@ static void intel_prepare_ddi_buffers(s
                bxt_ddi_vswing_sequence(dev, hdmi_level, port,
                                        INTEL_OUTPUT_HDMI);
                return;
 -      } else if (IS_SKYLAKE(dev)) {
 +      } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                ddi_translations_fdi = NULL;
                ddi_translations_dp =
                                skl_get_buf_trans_dp(dev, &n_dp_entries);
@@@ -576,7 -576,7 +576,7 @@@ void intel_prepare_ddi(struct drm_devic
  static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
                                    enum port port)
  {
 -      uint32_t reg = DDI_BUF_CTL(port);
 +      i915_reg_t reg = DDI_BUF_CTL(port);
        int i;
  
        for (i = 0; i < 16; i++) {
@@@ -931,8 -931,7 +931,8 @@@ static void hsw_wrpll_update_rnp(uint64
        /* Otherwise a < c && b >= d, do nothing */
  }
  
 -static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg)
 +static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
 +                                 i915_reg_t reg)
  {
        int refclk = LC_FREQ;
        int n, p, r;
  static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
                               uint32_t dpll)
  {
 -      uint32_t cfgcr1_reg, cfgcr2_reg;
 +      i915_reg_t cfgcr1_reg, cfgcr2_reg;
        uint32_t cfgcr1_val, cfgcr2_val;
        uint32_t p0, p1, p2, dco_freq;
  
@@@ -1113,10 -1112,10 +1113,10 @@@ static void hsw_ddi_clock_get(struct in
                link_clock = 270000;
                break;
        case PORT_CLK_SEL_WRPLL1:
 -              link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
 +              link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(0));
                break;
        case PORT_CLK_SEL_WRPLL2:
 -              link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
 +              link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(1));
                break;
        case PORT_CLK_SEL_SPLL:
                pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
@@@ -1185,7 -1184,7 +1185,7 @@@ void intel_ddi_clock_get(struct intel_e
  
        if (INTEL_INFO(dev)->gen <= 8)
                hsw_ddi_clock_get(encoder, pipe_config);
 -      else if (IS_SKYLAKE(dev))
 +      else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                skl_ddi_clock_get(encoder, pipe_config);
        else if (IS_BROXTON(dev))
                bxt_ddi_clock_get(encoder, pipe_config);
@@@ -1287,6 -1286,18 +1287,18 @@@ hsw_ddi_pll_select(struct intel_crtc *i
                }
  
                crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
+       } else if (crtc_state->ddi_pll_sel == PORT_CLK_SEL_SPLL) {
+               struct drm_atomic_state *state = crtc_state->base.state;
+               struct intel_shared_dpll_config *spll =
+                       &intel_atomic_get_shared_dpll_state(state)[DPLL_ID_SPLL];
+               if (spll->crtc_mask &&
+                   WARN_ON(spll->hw_state.spll != crtc_state->dpll_hw_state.spll))
+                       return false;
+               crtc_state->shared_dpll = DPLL_ID_SPLL;
+               spll->hw_state.spll = crtc_state->dpll_hw_state.spll;
+               spll->crtc_mask |= 1 << intel_crtc->pipe;
        }
  
        return true;
@@@ -1769,7 -1780,7 +1781,7 @@@ bool intel_ddi_pll_select(struct intel_
        struct intel_encoder *intel_encoder =
                intel_ddi_get_crtc_new_encoder(crtc_state);
  
 -      if (IS_SKYLAKE(dev))
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                return skl_ddi_pll_select(intel_crtc, crtc_state,
                                          intel_encoder);
        else if (IS_BROXTON(dev))
@@@ -1931,7 -1942,7 +1943,7 @@@ void intel_ddi_enable_transcoder_func(s
  void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
                                       enum transcoder cpu_transcoder)
  {
 -      uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
 +      i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
        uint32_t val = I915_READ(reg);
  
        val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
@@@ -2086,21 -2097,21 +2098,21 @@@ static void skl_ddi_set_iboost(struct d
                        iboost = dp_iboost;
                } else {
                        ddi_translations = skl_get_buf_trans_dp(dev, &n_entries);
 -                      iboost = ddi_translations[port].i_boost;
 +                      iboost = ddi_translations[level].i_boost;
                }
        } else if (type == INTEL_OUTPUT_EDP) {
                if (dp_iboost) {
                        iboost = dp_iboost;
                } else {
                        ddi_translations = skl_get_buf_trans_edp(dev, &n_entries);
 -                      iboost = ddi_translations[port].i_boost;
 +                      iboost = ddi_translations[level].i_boost;
                }
        } else if (type == INTEL_OUTPUT_HDMI) {
                if (hdmi_iboost) {
                        iboost = hdmi_iboost;
                } else {
                        ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries);
 -                      iboost = ddi_translations[port].i_boost;
 +                      iboost = ddi_translations[level].i_boost;
                }
        } else {
                return;
@@@ -2252,7 -2263,7 +2264,7 @@@ uint32_t ddi_signal_levels(struct intel
  
        level = translate_signal_level(signal_levels);
  
 -      if (IS_SKYLAKE(dev))
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                skl_ddi_set_iboost(dev, level, port, encoder->type);
        else if (IS_BROXTON(dev))
                bxt_ddi_vswing_sequence(dev, level, port, encoder->type);
        return DDI_BUF_TRANS_SELECT(level);
  }
  
 -static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 +void intel_ddi_clk_select(struct intel_encoder *encoder,
 +                        const struct intel_crtc_state *pipe_config)
  {
 -      struct drm_encoder *encoder = &intel_encoder->base;
 -      struct drm_device *dev = encoder->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 -      enum port port = intel_ddi_get_encoder_port(intel_encoder);
 -      int type = intel_encoder->type;
 -      int hdmi_level;
 -
 -      if (type == INTEL_OUTPUT_EDP) {
 -              struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 -              intel_edp_panel_on(intel_dp);
 -      }
 +      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 +      enum port port = intel_ddi_get_encoder_port(encoder);
  
 -      if (IS_SKYLAKE(dev)) {
 -              uint32_t dpll = crtc->config->ddi_pll_sel;
 +      if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
 +              uint32_t dpll = pipe_config->ddi_pll_sel;
                uint32_t val;
  
                /*
                 * DPLL0 is used for eDP and is the only "private" DPLL (as
                 * opposed to shared) on SKL
                 */
 -              if (type == INTEL_OUTPUT_EDP) {
 +              if (encoder->type == INTEL_OUTPUT_EDP) {
                        WARN_ON(dpll != SKL_DPLL0);
  
                        val = I915_READ(DPLL_CTRL1);
                        val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
                                 DPLL_CTRL1_SSC(dpll) |
                                 DPLL_CTRL1_LINK_RATE_MASK(dpll));
 -                      val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6);
 +                      val |= pipe_config->dpll_hw_state.ctrl1 << (dpll * 6);
  
                        I915_WRITE(DPLL_CTRL1, val);
                        POSTING_READ(DPLL_CTRL1);
  
                I915_WRITE(DPLL_CTRL2, val);
  
 -      } else if (INTEL_INFO(dev)->gen < 9) {
 -              WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE);
 -              I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel);
 +      } else if (INTEL_INFO(dev_priv)->gen < 9) {
 +              WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE);
 +              I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel);
        }
 +}
 +
 +static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 +{
 +      struct drm_encoder *encoder = &intel_encoder->base;
 +      struct drm_device *dev = encoder->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 +      enum port port = intel_ddi_get_encoder_port(intel_encoder);
 +      int type = intel_encoder->type;
 +      int hdmi_level;
 +
 +      if (type == INTEL_OUTPUT_EDP) {
 +              struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 +              intel_edp_panel_on(intel_dp);
 +      }
 +
 +      intel_ddi_clk_select(intel_encoder, crtc->config);
  
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@@ -2379,7 -2381,7 +2391,7 @@@ static void intel_ddi_post_disable(stru
                intel_edp_panel_off(intel_dp);
        }
  
 -      if (IS_SKYLAKE(dev))
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) |
                                        DPLL_CTRL2_DDI_CLK_OFF(port)));
        else if (INTEL_INFO(dev)->gen < 9)
@@@ -2447,7 -2449,7 +2459,7 @@@ static void intel_disable_ddi(struct in
        }
  }
  
- static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
+ static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
                               struct intel_shared_dpll *pll)
  {
        I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
        udelay(20);
  }
  
- static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
+ static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
                                struct intel_shared_dpll *pll)
+ {
+       I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
+       POSTING_READ(SPLL_CTL);
+       udelay(20);
+ }
+ static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
  {
        uint32_t val;
  
        POSTING_READ(WRPLL_CTL(pll->id));
  }
  
- static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
-                                    struct intel_shared_dpll *pll,
-                                    struct intel_dpll_hw_state *hw_state)
+ static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
+                                struct intel_shared_dpll *pll)
+ {
+       uint32_t val;
+       val = I915_READ(SPLL_CTL);
+       I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
+       POSTING_READ(SPLL_CTL);
+ }
+ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
+                                      struct intel_shared_dpll *pll,
+                                      struct intel_dpll_hw_state *hw_state)
  {
        uint32_t val;
  
        return val & WRPLL_PLL_ENABLE;
  }
  
+ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
+                                     struct intel_shared_dpll *pll,
+                                     struct intel_dpll_hw_state *hw_state)
+ {
+       uint32_t val;
+       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+               return false;
+       val = I915_READ(SPLL_CTL);
+       hw_state->spll = val;
+       return val & SPLL_PLL_ENABLE;
+ }
  static const char * const hsw_ddi_pll_names[] = {
        "WRPLL 1",
        "WRPLL 2",
+       "SPLL"
  };
  
  static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
  {
        int i;
  
-       dev_priv->num_shared_dpll = 2;
+       dev_priv->num_shared_dpll = 3;
  
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+       for (i = 0; i < 2; i++) {
                dev_priv->shared_dplls[i].id = i;
                dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
-               dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable;
-               dev_priv->shared_dplls[i].enable = hsw_ddi_pll_enable;
+               dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
+               dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
                dev_priv->shared_dplls[i].get_hw_state =
-                       hsw_ddi_pll_get_hw_state;
+                       hsw_ddi_wrpll_get_hw_state;
        }
+       /* SPLL is special, but needs to be initialized anyway.. */
+       dev_priv->shared_dplls[i].id = i;
+       dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
+       dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
+       dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
+       dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
  }
  
  static const char * const skl_ddi_pll_names[] = {
  };
  
  struct skl_dpll_regs {
 -      u32 ctl, cfgcr1, cfgcr2;
 +      i915_reg_t ctl, cfgcr1, cfgcr2;
  };
  
  /* this array is indexed by the *shared* pll id */
@@@ -2521,13 -2566,13 +2576,13 @@@ static const struct skl_dpll_regs skl_d
        },
        {
                /* DPLL 2 */
 -              .ctl = WRPLL_CTL1,
 +              .ctl = WRPLL_CTL(0),
                .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
                .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
        },
        {
                /* DPLL 3 */
 -              .ctl = WRPLL_CTL2,
 +              .ctl = WRPLL_CTL(1),
                .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
                .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
        },
@@@ -2947,22 -2992,22 +3002,22 @@@ void intel_ddi_pll_init(struct drm_devi
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t val = I915_READ(LCPLL_CTL);
  
 -      if (IS_SKYLAKE(dev))
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                skl_shared_dplls_init(dev_priv);
        else if (IS_BROXTON(dev))
                bxt_shared_dplls_init(dev_priv);
        else
                hsw_shared_dplls_init(dev_priv);
  
 -      if (IS_SKYLAKE(dev)) {
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                int cdclk_freq;
  
                cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
                dev_priv->skl_boot_cdclk = cdclk_freq;
 +              if (skl_sanitize_cdclk(dev_priv))
 +                      DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
                if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
                        DRM_ERROR("LCPLL1 is disabled\n");
 -              else
 -                      intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
        } else if (IS_BROXTON(dev)) {
                broxton_init_cdclk(dev);
                broxton_ddi_phy_init(dev);
        }
  }
  
 -void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder)
 +void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
  {
 -      struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 -      struct intel_dp *intel_dp = &intel_dig_port->dp;
 -      struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 +      struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 +      struct drm_i915_private *dev_priv =
 +              to_i915(intel_dig_port->base.base.dev);
        enum port port = intel_dig_port->port;
        uint32_t val;
        bool wait = false;
@@@ -3244,20 -3289,6 +3299,20 @@@ void intel_ddi_init(struct drm_device *
                                          (DDI_BUF_PORT_REVERSAL |
                                           DDI_A_4_LANES);
  
 +      /*
 +       * Bspec says that DDI_A_4_LANES is the only supported configuration
 +       * for Broxton.  Yet some BIOS fail to set this bit on port A if eDP
 +       * wasn't lit up at boot.  Force this bit on in our internal
 +       * configuration so that we use the proper lane count for our
 +       * calculations.
 +       */
 +      if (IS_BROXTON(dev) && port == PORT_A) {
 +              if (!(intel_dig_port->saved_port_bits & DDI_A_4_LANES)) {
 +                      DRM_DEBUG_KMS("BXT BIOS forgot to set DDI_A_4_LANES for port A; fixing\n");
 +                      intel_dig_port->saved_port_bits |= DDI_A_4_LANES;
 +              }
 +      }
 +
        intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        intel_encoder->cloneable = 0;
                 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
                 * interrupts to check the external panel connection.
                 */
 -              if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)
 -                                       && port == PORT_B)
 +              if (IS_BXT_REVID(dev, 0, BXT_REVID_A1) && port == PORT_B)
                        dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port;
                else
                        dev_priv->hotplug.irq_port[port] = intel_dig_port;
@@@ -1095,7 -1095,7 +1095,7 @@@ enum transcoder intel_pipe_to_cpu_trans
  static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 reg = PIPEDSL(pipe);
 +      i915_reg_t reg = PIPEDSL(pipe);
        u32 line1, line2;
        u32 line_mask;
  
@@@ -1135,7 -1135,7 +1135,7 @@@ static void intel_wait_for_pipe_off(str
        enum pipe pipe = crtc->pipe;
  
        if (INTEL_INFO(dev)->gen >= 4) {
 -              int reg = PIPECONF(cpu_transcoder);
 +              i915_reg_t reg = PIPECONF(cpu_transcoder);
  
                /* Wait for the Pipe State to go off */
                if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
@@@ -1285,7 -1285,7 +1285,7 @@@ void assert_panel_unlocked(struct drm_i
                           enum pipe pipe)
  {
        struct drm_device *dev = dev_priv->dev;
 -      int pp_reg;
 +      i915_reg_t pp_reg;
        u32 val;
        enum pipe panel_pipe = PIPE_A;
        bool locked = true;
@@@ -1480,7 -1480,8 +1480,7 @@@ static bool dp_pipe_enabled(struct drm_
                return false;
  
        if (HAS_PCH_CPT(dev_priv->dev)) {
 -              u32     trans_dp_ctl_reg = TRANS_DP_CTL(pipe);
 -              u32     trans_dp_ctl = I915_READ(trans_dp_ctl_reg);
 +              u32 trans_dp_ctl = I915_READ(TRANS_DP_CTL(pipe));
                if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel)
                        return false;
        } else if (IS_CHERRYVIEW(dev_priv->dev)) {
@@@ -1544,13 -1545,12 +1544,13 @@@ static bool adpa_pipe_enabled(struct dr
  }
  
  static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
 -                                 enum pipe pipe, int reg, u32 port_sel)
 +                                 enum pipe pipe, i915_reg_t reg,
 +                                 u32 port_sel)
  {
        u32 val = I915_READ(reg);
        I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
 -           reg, pipe_name(pipe));
 +           i915_mmio_reg_offset(reg), pipe_name(pipe));
  
        I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
             && (val & DP_PIPEB_SELECT),
  }
  
  static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
 -                                   enum pipe pipe, int reg)
 +                                   enum pipe pipe, i915_reg_t reg)
  {
        u32 val = I915_READ(reg);
        I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
             "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
 -           reg, pipe_name(pipe));
 +           i915_mmio_reg_offset(reg), pipe_name(pipe));
  
        I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
             && (val & SDVO_PIPE_B_SELECT),
@@@ -1599,7 -1599,7 +1599,7 @@@ static void vlv_enable_pll(struct intel
  {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      int reg = DPLL(crtc->pipe);
 +      i915_reg_t reg = DPLL(crtc->pipe);
        u32 dpll = pipe_config->dpll_hw_state.dpll;
  
        assert_pipe_disabled(dev_priv, crtc->pipe);
@@@ -1688,7 -1688,7 +1688,7 @@@ static void i9xx_enable_pll(struct inte
  {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      int reg = DPLL(crtc->pipe);
 +      i915_reg_t reg = DPLL(crtc->pipe);
        u32 dpll = crtc->config->dpll_hw_state.dpll;
  
        assert_pipe_disabled(dev_priv, crtc->pipe);
                           I915_READ(DPLL(!crtc->pipe)) | DPLL_DVO_2X_MODE);
        }
  
+       /*
+        * 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);
+       I915_WRITE(reg, dpll);
        /* Wait for the clocks to stabilize. */
        POSTING_READ(reg);
        udelay(150);
@@@ -1828,7 -1837,7 +1837,7 @@@ void vlv_wait_port_ready(struct drm_i91
                         unsigned int expected_mask)
  {
        u32 port_mask;
 -      int dpll_reg;
 +      i915_reg_t dpll_reg;
  
        switch (dport->port) {
        case PORT_B:
@@@ -1953,8 -1962,7 +1962,8 @@@ static void ironlake_enable_pch_transco
        struct drm_device *dev = dev_priv->dev;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      uint32_t reg, val, pipeconf_val;
 +      i915_reg_t reg;
 +      uint32_t val, pipeconf_val;
  
        /* PCH only available on ILK+ */
        BUG_ON(!HAS_PCH_SPLIT(dev));
@@@ -2043,8 -2051,7 +2052,8 @@@ static void ironlake_disable_pch_transc
                                            enum pipe pipe)
  {
        struct drm_device *dev = dev_priv->dev;
 -      uint32_t reg, val;
 +      i915_reg_t reg;
 +      uint32_t val;
  
        /* FDI relies on the transcoder */
        assert_fdi_tx_disabled(dev_priv, pipe);
        if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
                DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe));
  
 -      if (!HAS_PCH_IBX(dev)) {
 +      if (HAS_PCH_CPT(dev)) {
                /* Workaround: Clear the timing override chicken bit again. */
                reg = TRANS_CHICKEN2(pipe);
                val = I915_READ(reg);
@@@ -2099,9 -2106,10 +2108,9 @@@ static void intel_enable_pipe(struct in
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe = crtc->pipe;
 -      enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
 -                                                                    pipe);
 +      enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
        enum pipe pch_transcoder;
 -      int reg;
 +      i915_reg_t reg;
        u32 val;
  
        DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe));
@@@ -2162,7 -2170,7 +2171,7 @@@ static void intel_disable_pipe(struct i
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
        enum pipe pipe = crtc->pipe;
 -      int reg;
 +      i915_reg_t reg;
        u32 val;
  
        DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe));
@@@ -2261,20 -2269,20 +2270,20 @@@ intel_fb_align_height(struct drm_devic
                                               fb_format_modifier, 0));
  }
  
 -static int
 +static void
  intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
                        const struct drm_plane_state *plane_state)
  {
 -      struct intel_rotation_info *info = &view->rotation_info;
 +      struct intel_rotation_info *info = &view->params.rotation_info;
        unsigned int tile_height, tile_pitch;
  
        *view = i915_ggtt_view_normal;
  
        if (!plane_state)
 -              return 0;
 +              return;
  
        if (!intel_rotation_90_or_270(plane_state->rotation))
 -              return 0;
 +              return;
  
        *view = i915_ggtt_view_rotated;
  
                info->size_uv = info->width_pages_uv * info->height_pages_uv *
                                PAGE_SIZE;
        }
 -
 -      return 0;
  }
  
  static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv)
  int
  intel_pin_and_fence_fb_obj(struct drm_plane *plane,
                           struct drm_framebuffer *fb,
 -                         const struct drm_plane_state *plane_state,
 -                         struct intel_engine_cs *pipelined,
 -                         struct drm_i915_gem_request **pipelined_request)
 +                         const struct drm_plane_state *plane_state)
  {
        struct drm_device *dev = fb->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
                return -EINVAL;
        }
  
 -      ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
 -      if (ret)
 -              return ret;
 +      intel_fill_fb_ggtt_view(&view, fb, plane_state);
  
        /* 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
         */
        intel_runtime_pm_get(dev_priv);
  
 -      dev_priv->mm.interruptible = false;
 -      ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined,
 -                                                 pipelined_request, &view);
 +      ret = i915_gem_object_pin_to_display_plane(obj, alignment,
 +                                                 &view);
        if (ret)
 -              goto err_interruptible;
 +              goto err_pm;
  
        /* 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 install
         * a fence as the cost is not that onerous.
         */
-       ret = i915_gem_object_get_fence(obj);
-       if (ret == -EDEADLK) {
-               /*
-                * -EDEADLK means there are no free fences
-                * no pending flips.
-                *
-                * This is propagated to atomic, but it uses
-                * -EDEADLK to force a locking recovery, so
-                * change the returned error to -EBUSY.
-                */
-               ret = -EBUSY;
-               goto err_unpin;
-       } else if (ret)
-               goto err_unpin;
+       if (view.type == I915_GGTT_VIEW_NORMAL) {
+               ret = i915_gem_object_get_fence(obj);
+               if (ret == -EDEADLK) {
+                       /*
+                        * -EDEADLK means there are no free fences
+                        * no pending flips.
+                        *
+                        * This is propagated to atomic, but it uses
+                        * -EDEADLK to force a locking recovery, so
+                        * change the returned error to -EBUSY.
+                        */
+                       ret = -EBUSY;
+                       goto err_unpin;
+               } else if (ret)
+                       goto err_unpin;
  
-       i915_gem_object_pin_fence(obj);
+               i915_gem_object_pin_fence(obj);
+       }
  
 -      dev_priv->mm.interruptible = true;
        intel_runtime_pm_put(dev_priv);
        return 0;
  
  err_unpin:
        i915_gem_object_unpin_from_display_plane(obj, &view);
 -err_interruptible:
 -      dev_priv->mm.interruptible = true;
 +err_pm:
        intel_runtime_pm_put(dev_priv);
        return ret;
  }
@@@ -2415,12 -2434,16 +2426,14 @@@ static void intel_unpin_fb_obj(struct d
  {
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct i915_ggtt_view view;
 -      int ret;
  
        WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
  
 -      ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
 -      WARN_ONCE(ret, "Couldn't get view from plane state!");
 +      intel_fill_fb_ggtt_view(&view, fb, plane_state);
  
-       i915_gem_object_unpin_fence(obj);
+       if (view.type == I915_GGTT_VIEW_NORMAL)
+               i915_gem_object_unpin_fence(obj);
        i915_gem_object_unpin_from_display_plane(obj, &view);
  }
  
@@@ -2623,11 -2646,13 +2636,13 @@@ intel_find_initial_plane_obj(struct int
        return;
  
  valid_fb:
-       plane_state->src_x = plane_state->src_y = 0;
+       plane_state->src_x = 0;
+       plane_state->src_y = 0;
        plane_state->src_w = fb->width << 16;
        plane_state->src_h = fb->height << 16;
  
-       plane_state->crtc_x = plane_state->src_y = 0;
+       plane_state->crtc_x = 0;
+       plane_state->crtc_y = 0;
        plane_state->crtc_w = fb->width;
        plane_state->crtc_h = fb->height;
  
@@@ -2655,7 -2680,7 +2670,7 @@@ static void i9xx_update_primary_plane(s
        int plane = intel_crtc->plane;
        unsigned long linear_offset;
        u32 dspcntr;
 -      u32 reg = DSPCNTR(plane);
 +      i915_reg_t reg = DSPCNTR(plane);
        int pixel_size;
  
        if (!visible || !fb) {
@@@ -2785,7 -2810,7 +2800,7 @@@ static void ironlake_update_primary_pla
        int plane = intel_crtc->plane;
        unsigned long linear_offset;
        u32 dspcntr;
 -      u32 reg = DSPCNTR(plane);
 +      i915_reg_t reg = DSPCNTR(plane);
        int pixel_size;
  
        if (!visible || !fb) {
@@@ -2910,32 -2935,30 +2925,32 @@@ u32 intel_fb_stride_alignment(struct dr
        }
  }
  
 -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
 -                                   struct drm_i915_gem_object *obj,
 -                                   unsigned int plane)
 +u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
 +                         struct drm_i915_gem_object *obj,
 +                         unsigned int plane)
  {
 -      const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
 +      struct i915_ggtt_view view;
        struct i915_vma *vma;
 -      unsigned char *offset;
 +      u64 offset;
  
 -      if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
 -              view = &i915_ggtt_view_rotated;
 +      intel_fill_fb_ggtt_view(&view, intel_plane->base.fb,
 +                              intel_plane->base.state);
  
 -      vma = i915_gem_obj_to_ggtt_view(obj, view);
 +      vma = i915_gem_obj_to_ggtt_view(obj, &view);
        if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
 -              view->type))
 +              view.type))
                return -1;
  
 -      offset = (unsigned char *)vma->node.start;
 +      offset = vma->node.start;
  
        if (plane == 1) {
 -              offset += vma->ggtt_view.rotation_info.uv_start_page *
 +              offset += vma->ggtt_view.params.rotation_info.uv_start_page *
                          PAGE_SIZE;
        }
  
 -      return (unsigned long)offset;
 +      WARN_ON(upper_32_bits(offset));
 +
 +      return lower_32_bits(offset);
  }
  
  static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@@ -3061,7 -3084,7 +3076,7 @@@ static void skylake_update_primary_plan
        u32 tile_height, plane_offset, plane_size;
        unsigned int rotation;
        int x_offset, y_offset;
 -      unsigned long surf_addr;
 +      u32 surf_addr;
        struct intel_crtc_state *crtc_state = intel_crtc->config;
        struct intel_plane_state *plane_state;
        int src_x = 0, src_y = 0, src_w = 0, src_h = 0;
@@@ -3189,9 -3212,10 +3204,9 @@@ static void intel_update_primary_planes
                struct intel_plane_state *plane_state;
  
                drm_modeset_lock_crtc(crtc, &plane->base);
 -
                plane_state = to_intel_plane_state(plane->base.state);
  
 -              if (plane_state->base.fb)
 +              if (crtc->state->active && plane_state->base.fb)
                        plane->commit_plane(&plane->base, plane_state);
  
                drm_modeset_unlock_crtc(crtc);
@@@ -3267,6 -3291,32 +3282,6 @@@ void intel_finish_reset(struct drm_devi
        drm_modeset_unlock_all(dev);
  }
  
 -static void
 -intel_finish_fb(struct drm_framebuffer *old_fb)
 -{
 -      struct drm_i915_gem_object *obj = intel_fb_obj(old_fb);
 -      struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
 -      bool was_interruptible = dev_priv->mm.interruptible;
 -      int ret;
 -
 -      /* 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.
 -       */
 -      dev_priv->mm.interruptible = false;
 -      ret = i915_gem_object_wait_rendering(obj, true);
 -      dev_priv->mm.interruptible = was_interruptible;
 -
 -      WARN_ON(ret);
 -}
 -
  static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
@@@ -3336,8 -3386,7 +3351,8 @@@ static void intel_fdi_normal_train(stru
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp;
 +      i915_reg_t reg;
 +      u32 temp;
  
        /* enable normal train */
        reg = FDI_TX_CTL(pipe);
@@@ -3379,8 -3428,7 +3394,8 @@@ static void ironlake_fdi_link_train(str
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp, tries;
 +      i915_reg_t reg;
 +      u32 temp, tries;
  
        /* FDI needs bits from pipe first */
        assert_pipe_enabled(dev_priv, pipe);
@@@ -3480,8 -3528,7 +3495,8 @@@ static void gen6_fdi_link_train(struct 
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp, i, retry;
 +      i915_reg_t reg;
 +      u32 temp, i, retry;
  
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
@@@ -3613,8 -3660,7 +3628,8 @@@ static void ivb_manual_fdi_link_train(s
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp, i, j;
 +      i915_reg_t reg;
 +      u32 temp, i, j;
  
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
@@@ -3731,8 -3777,8 +3746,8 @@@ static void ironlake_fdi_pll_enable(str
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp;
 -
 +      i915_reg_t reg;
 +      u32 temp;
  
        /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
        reg = FDI_RX_CTL(pipe);
@@@ -3768,8 -3814,7 +3783,8 @@@ static void ironlake_fdi_pll_disable(st
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp;
 +      i915_reg_t reg;
 +      u32 temp;
  
        /* Switch from PCDclk to Rawclk */
        reg = FDI_RX_CTL(pipe);
@@@ -3799,8 -3844,7 +3814,8 @@@ static void ironlake_fdi_disable(struc
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp;
 +      i915_reg_t reg;
 +      u32 temp;
  
        /* disable CPU FDI tx and PCH FDI rx */
        reg = FDI_TX_CTL(pipe);
@@@ -3893,23 -3937,15 +3908,23 @@@ static void page_flip_completed(struct 
                                 work->pending_flip_obj);
  }
  
 -void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 +static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      long ret;
  
        WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
 -      if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
 -                                     !intel_crtc_has_pending_flip(crtc),
 -                                     60*HZ) == 0)) {
 +
 +      ret = wait_event_interruptible_timeout(
 +                                      dev_priv->pending_flip_queue,
 +                                      !intel_crtc_has_pending_flip(crtc),
 +                                      60*HZ);
 +
 +      if (ret < 0)
 +              return ret;
 +
 +      if (ret == 0) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  
                spin_lock_irq(&dev->event_lock);
                spin_unlock_irq(&dev->event_lock);
        }
  
 -      if (crtc->primary->fb) {
 -              mutex_lock(&dev->struct_mutex);
 -              intel_finish_fb(crtc->primary->fb);
 -              mutex_unlock(&dev->struct_mutex);
 -      }
 +      return 0;
  }
  
  /* Program iCLKIP clock to the desired frequency */
@@@ -4080,22 -4120,6 +4095,22 @@@ static void ivybridge_update_fdi_bc_bif
        }
  }
  
 +/* Return which DP Port should be selected for Transcoder DP control */
 +static enum port
 +intel_trans_dp_port_sel(struct drm_crtc *crtc)
 +{
 +      struct drm_device *dev = crtc->dev;
 +      struct intel_encoder *encoder;
 +
 +      for_each_encoder_on_crtc(dev, crtc, encoder) {
 +              if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
 +                  encoder->type == INTEL_OUTPUT_EDP)
 +                      return enc_to_dig_port(&encoder->base)->port;
 +      }
 +
 +      return -1;
 +}
 +
  /*
   * Enable PCH resources required for PCH ports:
   *   - PCH PLLs
@@@ -4110,7 -4134,7 +4125,7 @@@ static void ironlake_pch_enable(struct 
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp;
 +      u32 temp;
  
        assert_pch_transcoder_disabled(dev_priv, pipe);
  
  
        /* For PCH DP, enable TRANS_DP_CTL */
        if (HAS_PCH_CPT(dev) && intel_crtc->config->has_dp_encoder) {
 +              const struct drm_display_mode *adjusted_mode =
 +                      &intel_crtc->config->base.adjusted_mode;
                u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5;
 -              reg = TRANS_DP_CTL(pipe);
 +              i915_reg_t reg = TRANS_DP_CTL(pipe);
                temp = I915_READ(reg);
                temp &= ~(TRANS_DP_PORT_SEL_MASK |
                          TRANS_DP_SYNC_MASK |
                temp |= TRANS_DP_OUTPUT_ENABLE;
                temp |= bpc << 9; /* same format but at 11:9 */
  
 -              if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
 +              if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                        temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
 -              if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
 +              if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                        temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
  
                switch (intel_trans_dp_port_sel(crtc)) {
 -              case PCH_DP_B:
 +              case PORT_B:
                        temp |= TRANS_DP_PORT_SEL_B;
                        break;
 -              case PCH_DP_C:
 +              case PORT_C:
                        temp |= TRANS_DP_PORT_SEL_C;
                        break;
 -              case PCH_DP_D:
 +              case PORT_D:
                        temp |= TRANS_DP_PORT_SEL_D;
                        break;
                default:
@@@ -4217,6 -4239,7 +4232,7 @@@ struct intel_shared_dpll *intel_get_sha
        struct intel_shared_dpll *pll;
        struct intel_shared_dpll_config *shared_dpll;
        enum intel_dpll_id i;
+       int max = dev_priv->num_shared_dpll;
  
        shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
  
                WARN_ON(shared_dpll[i].crtc_mask);
  
                goto found;
-       }
+       } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
+               /* Do not consider SPLL */
+               max = 2;
  
-       for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+       for (i = 0; i < max; i++) {
                pll = &dev_priv->shared_dplls[i];
  
                /* Only want to check enabled timings first */
@@@ -4317,7 -4342,7 +4335,7 @@@ static void intel_shared_dpll_commit(st
  static void cpt_verify_modeset(struct drm_device *dev, int pipe)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      int dslreg = PIPEDSL(pipe);
 +      i915_reg_t dslreg = PIPEDSL(pipe);
        u32 temp;
  
        temp = I915_READ(dslreg);
@@@ -4627,7 -4652,7 +4645,7 @@@ static void intel_crtc_load_lut(struct 
        }
  
        for (i = 0; i < 256; i++) {
 -              u32 palreg;
 +              i915_reg_t palreg;
  
                if (HAS_GMCH_DISPLAY(dev))
                        palreg = PALETTE(pipe, i);
@@@ -4706,9 -4731,9 +4724,9 @@@ intel_post_enable_primary(struct drm_cr
        if (IS_GEN2(dev))
                intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
  
 -      /* Underruns don't raise interrupts, so check manually. */
 -      if (HAS_GMCH_DISPLAY(dev))
 -              i9xx_check_fifo_underruns(dev_priv);
 +      /* Underruns don't always raise interrupts, so check manually. */
 +      intel_check_cpu_fifo_underruns(dev_priv);
 +      intel_check_pch_fifo_underruns(dev_priv);
  }
  
  /**
@@@ -4767,6 -4792,7 +4785,6 @@@ static void intel_post_plane_update(str
        struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_plane *plane;
  
        if (atomic->wait_vblank)
                intel_wait_for_vblank(dev, crtc->pipe);
        if (atomic->post_enable_primary)
                intel_post_enable_primary(&crtc->base);
  
 -      drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks)
 -              intel_update_sprite_watermarks(plane, &crtc->base,
 -                                             0, 0, 0, false, false);
 -
        memset(atomic, 0, sizeof(*atomic));
  }
  
@@@ -4793,6 -4823,20 +4811,6 @@@ static void intel_pre_plane_update(stru
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
 -      struct drm_plane *p;
 -
 -      /* Track fb's for any planes being disabled */
 -      drm_for_each_plane_mask(p, dev, atomic->disabled_planes) {
 -              struct intel_plane *plane = to_intel_plane(p);
 -
 -              mutex_lock(&dev->struct_mutex);
 -              i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL,
 -                                plane->frontbuffer_bit);
 -              mutex_unlock(&dev->struct_mutex);
 -      }
 -
 -      if (atomic->wait_for_flips)
 -              intel_crtc_wait_for_pending_flips(&crtc->base);
  
        if (atomic->disable_fbc)
                intel_fbc_disable_crtc(crtc);
@@@ -4840,9 -4884,6 +4858,9 @@@ static void ironlake_crtc_enable(struc
        if (WARN_ON(intel_crtc->active))
                return;
  
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 +
        if (intel_crtc->config->has_pch_encoder)
                intel_prepare_shared_dpll(intel_crtc);
  
        intel_crtc->active = true;
  
        intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 -      intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
  
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
  
        if (HAS_PCH_CPT(dev))
                cpt_verify_modeset(dev, intel_crtc->pipe);
 +
 +      /* Must wait for vblank to avoid spurious PCH FIFO underruns */
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_wait_for_vblank(dev, pipe);
 +      intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
  }
  
  /* IPS only exists on ULT machines and is tied to pipe A. */
@@@ -4925,10 -4962,6 +4943,10 @@@ static void haswell_crtc_enable(struct 
        if (WARN_ON(intel_crtc->active))
                return;
  
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 +                                                    false);
 +
        if (intel_crtc_to_shared_dpll(intel_crtc))
                intel_enable_shared_dpll(intel_crtc);
  
                        encoder->pre_enable(encoder);
        }
  
 -      if (intel_crtc->config->has_pch_encoder) {
 -              intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 -                                                    true);
 +      if (intel_crtc->config->has_pch_encoder)
                dev_priv->display.fdi_link_train(crtc);
 -      }
  
        if (!is_dsi)
                intel_ddi_enable_pipe_clock(intel_crtc);
                intel_opregion_notify_encoder(encoder, true);
        }
  
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 +                                                    true);
 +
        /* If we change the relative order between pipe/planes enabling, we need
         * to change the workaround. */
        hsw_workaround_pipe = pipe_config->hsw_workaround_pipe;
@@@ -5034,9 -5066,7 +5052,9 @@@ static void ironlake_crtc_disable(struc
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
 -      u32 reg, temp;
 +
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
  
        for_each_encoder_on_crtc(dev, crtc, encoder)
                encoder->disable(encoder);
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
  
 -      if (intel_crtc->config->has_pch_encoder)
 -              intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 -
        intel_disable_pipe(intel_crtc);
  
        ironlake_pfit_disable(intel_crtc, false);
                ironlake_disable_pch_transcoder(dev_priv, pipe);
  
                if (HAS_PCH_CPT(dev)) {
 +                      i915_reg_t reg;
 +                      u32 temp;
 +
                        /* disable TRANS_DP_CTL */
                        reg = TRANS_DP_CTL(pipe);
                        temp = I915_READ(reg);
  
                ironlake_fdi_pll_disable(intel_crtc);
        }
 +
 +      intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
  }
  
  static void haswell_crtc_disable(struct drm_crtc *crtc)
        enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
        bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
  
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 +                                                    false);
 +
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                intel_opregion_notify_encoder(encoder, false);
                encoder->disable(encoder);
        drm_crtc_vblank_off(crtc);
        assert_vblank_disabled(crtc);
  
 -      if (intel_crtc->config->has_pch_encoder)
 -              intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 -                                                    false);
        intel_disable_pipe(intel_crtc);
  
        if (intel_crtc->config->dp_encoder_is_mst)
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->post_disable)
                        encoder->post_disable(encoder);
 +
 +      if (intel_crtc->config->has_pch_encoder)
 +              intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 +                                                    true);
  }
  
  static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@@ -5161,41 -5184,21 +5179,41 @@@ static enum intel_display_power_domain 
  {
        switch (port) {
        case PORT_A:
 -              return POWER_DOMAIN_PORT_DDI_A_4_LANES;
 +              return POWER_DOMAIN_PORT_DDI_A_LANES;
        case PORT_B:
 -              return POWER_DOMAIN_PORT_DDI_B_4_LANES;
 +              return POWER_DOMAIN_PORT_DDI_B_LANES;
        case PORT_C:
 -              return POWER_DOMAIN_PORT_DDI_C_4_LANES;
 +              return POWER_DOMAIN_PORT_DDI_C_LANES;
        case PORT_D:
 -              return POWER_DOMAIN_PORT_DDI_D_4_LANES;
 +              return POWER_DOMAIN_PORT_DDI_D_LANES;
        case PORT_E:
 -              return POWER_DOMAIN_PORT_DDI_E_2_LANES;
 +              return POWER_DOMAIN_PORT_DDI_E_LANES;
        default:
 -              WARN_ON_ONCE(1);
 +              MISSING_CASE(port);
                return POWER_DOMAIN_PORT_OTHER;
        }
  }
  
 +static enum intel_display_power_domain port_to_aux_power_domain(enum port port)
 +{
 +      switch (port) {
 +      case PORT_A:
 +              return POWER_DOMAIN_AUX_A;
 +      case PORT_B:
 +              return POWER_DOMAIN_AUX_B;
 +      case PORT_C:
 +              return POWER_DOMAIN_AUX_C;
 +      case PORT_D:
 +              return POWER_DOMAIN_AUX_D;
 +      case PORT_E:
 +              /* FIXME: Check VBT for actual wiring of PORT E */
 +              return POWER_DOMAIN_AUX_D;
 +      default:
 +              MISSING_CASE(port);
 +              return POWER_DOMAIN_AUX_A;
 +      }
 +}
 +
  #define for_each_power_domain(domain, mask)                           \
        for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++)     \
                if ((1 << (domain)) & (mask))
@@@ -5227,36 -5230,6 +5245,36 @@@ intel_display_port_power_domain(struct 
        }
  }
  
 +enum intel_display_power_domain
 +intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder)
 +{
 +      struct drm_device *dev = intel_encoder->base.dev;
 +      struct intel_digital_port *intel_dig_port;
 +
 +      switch (intel_encoder->type) {
 +      case INTEL_OUTPUT_UNKNOWN:
 +      case INTEL_OUTPUT_HDMI:
 +              /*
 +               * Only DDI platforms should ever use these output types.
 +               * We can get here after the HDMI detect code has already set
 +               * the type of the shared encoder. Since we can't be sure
 +               * what's the status of the given connectors, play safe and
 +               * run the DP detection too.
 +               */
 +              WARN_ON_ONCE(!HAS_DDI(dev));
 +      case INTEL_OUTPUT_DISPLAYPORT:
 +      case INTEL_OUTPUT_EDP:
 +              intel_dig_port = enc_to_dig_port(&intel_encoder->base);
 +              return port_to_aux_power_domain(intel_dig_port->port);
 +      case INTEL_OUTPUT_DP_MST:
 +              intel_dig_port = enc_to_mst(&intel_encoder->base)->primary;
 +              return port_to_aux_power_domain(intel_dig_port->port);
 +      default:
 +              MISSING_CASE(intel_encoder->type);
 +              return POWER_DOMAIN_AUX_A;
 +      }
 +}
 +
  static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
        unsigned long mask;
 -      enum transcoder transcoder;
 +      enum transcoder transcoder = intel_crtc->config->cpu_transcoder;
  
        if (!crtc->state->active)
                return 0;
  
 -      transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
 -
        mask = BIT(POWER_DOMAIN_PIPE(pipe));
        mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
        if (intel_crtc->config->pch_pfit.enabled ||
@@@ -5355,7 -5330,7 +5373,7 @@@ static void intel_update_max_cdclk(stru
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
 -      if (IS_SKYLAKE(dev)) {
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
  
                if (limit == SKL_DFSM_CDCLK_LIMIT_675)
@@@ -5772,16 -5747,32 +5790,16 @@@ void skl_uninit_cdclk(struct drm_i915_p
        if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE)
                DRM_ERROR("DBuf power disable timeout\n");
  
 -      /*
 -       * DMC assumes ownership of LCPLL and will get confused if we touch it.
 -       */
 -      if (dev_priv->csr.dmc_payload) {
 -              /* disable DPLL0 */
 -              I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) &
 -                                      ~LCPLL_PLL_ENABLE);
 -              if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
 -                      DRM_ERROR("Couldn't disable DPLL0\n");
 -      }
 -
 -      intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
 +      /* disable DPLL0 */
 +      I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
 +      if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
 +              DRM_ERROR("Couldn't disable DPLL0\n");
  }
  
  void skl_init_cdclk(struct drm_i915_private *dev_priv)
  {
 -      u32 val;
        unsigned int required_vco;
  
 -      /* enable PCH reset handshake */
 -      val = I915_READ(HSW_NDE_RSTWRN_OPT);
 -      I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
 -
 -      /* enable PG1 and Misc I/O */
 -      intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
 -
        /* DPLL0 not enabled (happens on early BIOS versions) */
        if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) {
                /* enable DPLL0 */
                DRM_ERROR("DBuf power enable timeout\n");
  }
  
 +int skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
 +{
 +      uint32_t lcpll1 = I915_READ(LCPLL1_CTL);
 +      uint32_t cdctl = I915_READ(CDCLK_CTL);
 +      int freq = dev_priv->skl_boot_cdclk;
 +
 +      /*
 +       * check if the pre-os intialized the display
 +       * There is SWF18 scratchpad register defined which is set by the
 +       * pre-os which can be used by the OS drivers to check the status
 +       */
 +      if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0)
 +              goto sanitize;
 +
 +      /* Is PLL enabled and locked ? */
 +      if (!((lcpll1 & LCPLL_PLL_ENABLE) && (lcpll1 & LCPLL_PLL_LOCK)))
 +              goto sanitize;
 +
 +      /* DPLL okay; verify the cdclock
 +       *
 +       * Noticed in some instances that the freq selection is correct but
 +       * decimal part is programmed wrong from BIOS where pre-os does not
 +       * enable display. Verify the same as well.
 +       */
 +      if (cdctl == ((cdctl & CDCLK_FREQ_SEL_MASK) | skl_cdclk_decimal(freq)))
 +              /* All well; nothing to sanitize */
 +              return false;
 +sanitize:
 +      /*
 +       * As of now initialize with max cdclk till
 +       * we get dynamic cdclk support
 +       * */
 +      dev_priv->skl_boot_cdclk = dev_priv->max_cdclk_freq;
 +      skl_init_cdclk(dev_priv);
 +
 +      /* we did have to sanitize */
 +      return true;
 +}
 +
  /* Adjust CDclk dividers to allow high res or save power if possible */
  static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
  {
@@@ -6305,8 -6257,7 +6323,8 @@@ static void intel_crtc_disable_noatomic
                return;
  
        if (to_intel_plane_state(crtc->primary->state)->visible) {
 -              intel_crtc_wait_for_pending_flips(crtc);
 +              WARN_ON(intel_crtc->unpin_work);
 +
                intel_pre_disable_primary(crtc);
        }
  
@@@ -6624,15 -6575,6 +6642,15 @@@ static void hsw_compute_ips_config(stru
                pipe_config_supports_ips(dev_priv, pipe_config);
  }
  
 +static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
 +{
 +      const struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 +
 +      /* GDG double wide on either pipe, otherwise pipe A only */
 +      return INTEL_INFO(dev_priv)->gen < 4 &&
 +              (crtc->pipe == PIPE_A || IS_I915G(dev_priv));
 +}
 +
  static int intel_crtc_compute_config(struct intel_crtc *crtc,
                                     struct intel_crtc_state *pipe_config)
  {
  
        /* FIXME should check pixel clock limits on all platforms */
        if (INTEL_INFO(dev)->gen < 4) {
 -              int clock_limit = dev_priv->max_cdclk_freq;
 +              int clock_limit = dev_priv->max_cdclk_freq * 9 / 10;
  
                /*
 -               * Enable pixel doubling when the dot clock
 +               * Enable double wide mode when the dot clock
                 * is > 90% of the (display) core speed.
 -               *
 -               * GDG double wide on either pipe,
 -               * otherwise pipe A only.
                 */
 -              if ((crtc->pipe == PIPE_A || IS_I915G(dev)) &&
 -                  adjusted_mode->crtc_clock > clock_limit * 9 / 10) {
 +              if (intel_crtc_supports_double_wide(crtc) &&
 +                  adjusted_mode->crtc_clock > clock_limit) {
                        clock_limit *= 2;
                        pipe_config->double_wide = true;
                }
  
 -              if (adjusted_mode->crtc_clock > clock_limit * 9 / 10)
 +              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;
 +              }
        }
  
        /*
@@@ -7424,7 -7365,7 +7442,7 @@@ static void chv_prepare_pll(struct inte
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe = crtc->pipe;
 -      int dpll_reg = DPLL(crtc->pipe);
 +      i915_reg_t dpll_reg = DPLL(crtc->pipe);
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
        u32 loopfilter, tribuf_calcntr;
        u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
@@@ -9342,8 -9283,8 +9360,8 @@@ static void assert_can_disable_lcpll(st
  
        I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
        I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
 -      I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
 -      I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
 +      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");
        I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
        I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
             "CPU PWM1 enabled\n");
@@@ -9787,6 -9728,8 +9805,8 @@@ static void haswell_get_ddi_pll(struct 
        case PORT_CLK_SEL_WRPLL2:
                pipe_config->shared_dpll = DPLL_ID_WRPLL2;
                break;
+       case PORT_CLK_SEL_SPLL:
+               pipe_config->shared_dpll = DPLL_ID_SPLL;
        }
  }
  
@@@ -9803,7 -9746,7 +9823,7 @@@ static void haswell_get_ddi_port_state(
  
        port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT;
  
 -      if (IS_SKYLAKE(dev))
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                skylake_get_ddi_pll(dev_priv, port, pipe_config);
        else if (IS_BROXTON(dev))
                bxt_get_ddi_pll(dev_priv, port, pipe_config);
@@@ -10149,17 -10092,20 +10169,17 @@@ __intel_framebuffer_create(struct drm_d
        int ret;
  
        intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
 -      if (!intel_fb) {
 -              drm_gem_object_unreference(&obj->base);
 +      if (!intel_fb)
                return ERR_PTR(-ENOMEM);
 -      }
  
        ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
        if (ret)
                goto err;
  
        return &intel_fb->base;
 +
  err:
 -      drm_gem_object_unreference(&obj->base);
        kfree(intel_fb);
 -
        return ERR_PTR(ret);
  }
  
@@@ -10199,7 -10145,6 +10219,7 @@@ intel_framebuffer_create_for_mode(struc
                                  struct drm_display_mode *mode,
                                  int depth, int bpp)
  {
 +      struct drm_framebuffer *fb;
        struct drm_i915_gem_object *obj;
        struct drm_mode_fb_cmd2 mode_cmd = { 0 };
  
                                                                bpp);
        mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
  
 -      return intel_framebuffer_create(dev, &mode_cmd, obj);
 +      fb = intel_framebuffer_create(dev, &mode_cmd, obj);
 +      if (IS_ERR(fb))
 +              drm_gem_object_unreference_unlocked(&obj->base);
 +
 +      return fb;
  }
  
  static struct drm_framebuffer *
@@@ -11121,7 -11062,7 +11141,7 @@@ static int intel_gen7_queue_flip(struc
         */
        if (ring->id == RCS) {
                intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
 -              intel_ring_emit(ring, DERRMR);
 +              intel_ring_emit_reg(ring, DERRMR);
                intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
                                        DERRMR_PIPEB_PRI_FLIP_DONE |
                                        DERRMR_PIPEC_PRI_FLIP_DONE));
                else
                        intel_ring_emit(ring, MI_STORE_REGISTER_MEM |
                                              MI_SRM_LRM_GLOBAL_GTT);
 -              intel_ring_emit(ring, DERRMR);
 +              intel_ring_emit_reg(ring, DERRMR);
                intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
                if (IS_GEN8(dev)) {
                        intel_ring_emit(ring, 0);
@@@ -11176,14 -11117,13 +11196,14 @@@ static bool use_mmio_flip(struct intel_
  }
  
  static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
 +                           unsigned int rotation,
                             struct intel_unpin_work *work)
  {
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
        const enum pipe pipe = intel_crtc->pipe;
 -      u32 ctl, stride;
 +      u32 ctl, stride, tile_height;
  
        ctl = I915_READ(PLANE_CTL(pipe, 0));
        ctl &= ~PLANE_CTL_TILED_MASK;
         * The stride is either expressed as a multiple of 64 bytes chunks for
         * linear buffers or in number of tiles for tiled buffers.
         */
 -      stride = fb->pitches[0] /
 -               intel_fb_stride_alignment(dev, fb->modifier[0],
 -                                         fb->pixel_format);
 +      if (intel_rotation_90_or_270(rotation)) {
 +              /* stride = Surface height in tiles */
 +              tile_height = intel_tile_height(dev, fb->pixel_format,
 +                                              fb->modifier[0], 0);
 +              stride = DIV_ROUND_UP(fb->height, tile_height);
 +      } else {
 +              stride = fb->pitches[0] /
 +                              intel_fb_stride_alignment(dev, fb->modifier[0],
 +                                                        fb->pixel_format);
 +      }
  
        /*
         * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
@@@ -11237,9 -11170,10 +11257,9 @@@ static void ilk_do_mmio_flip(struct int
        struct intel_framebuffer *intel_fb =
                to_intel_framebuffer(intel_crtc->base.primary->fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
 +      i915_reg_t reg = DSPCNTR(intel_crtc->plane);
        u32 dspcntr;
 -      u32 reg;
  
 -      reg = DSPCNTR(intel_crtc->plane);
        dspcntr = I915_READ(reg);
  
        if (obj->tiling_mode != I915_TILING_NONE)
@@@ -11273,7 -11207,7 +11293,7 @@@ static void intel_do_mmio_flip(struct i
        intel_pipe_update_start(crtc);
  
        if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
 -              skl_do_mmio_flip(crtc, work);
 +              skl_do_mmio_flip(crtc, mmio_flip->rotation, work);
        else
                /* use_mmio_flip() retricts MMIO flips to ilk+ */
                ilk_do_mmio_flip(crtc, work);
@@@ -11300,7 -11234,10 +11320,7 @@@ static void intel_mmio_flip_work_func(s
  
  static int intel_queue_mmio_flip(struct drm_device *dev,
                                 struct drm_crtc *crtc,
 -                               struct drm_framebuffer *fb,
 -                               struct drm_i915_gem_object *obj,
 -                               struct intel_engine_cs *ring,
 -                               uint32_t flags)
 +                               struct drm_i915_gem_object *obj)
  {
        struct intel_mmio_flip *mmio_flip;
  
        mmio_flip->i915 = to_i915(dev);
        mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
        mmio_flip->crtc = to_intel_crtc(crtc);
 +      mmio_flip->rotation = crtc->primary->state->rotation;
  
        INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
        schedule_work(&mmio_flip->work);
@@@ -11517,14 -11453,9 +11537,14 @@@ static int intel_crtc_page_flip(struct 
         * synchronisation, so all we want here is to pin the framebuffer
         * into the display plane and skip any waits.
         */
 +      if (!mmio_flip) {
 +              ret = i915_gem_object_sync(obj, ring, &request);
 +              if (ret)
 +                      goto cleanup_pending;
 +      }
 +
        ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
 -                                       crtc->primary->state,
 -                                       mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring, &request);
 +                                       crtc->primary->state);
        if (ret)
                goto cleanup_pending;
  
        work->gtt_offset += intel_crtc->dspaddr_offset;
  
        if (mmio_flip) {
 -              ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
 -                                          page_flip_flags);
 +              ret = intel_queue_mmio_flip(dev, crtc, obj);
                if (ret)
                        goto cleanup_unpin;
  
  static bool intel_wm_need_update(struct drm_plane *plane,
                                 struct drm_plane_state *state)
  {
 -      /* Update watermarks on tiling changes. */
 +      struct intel_plane_state *new = to_intel_plane_state(state);
 +      struct intel_plane_state *cur = to_intel_plane_state(plane->state);
 +
 +      /* Update watermarks on tiling or size changes. */
        if (!plane->state->fb || !state->fb ||
            plane->state->fb->modifier[0] != state->fb->modifier[0] ||
 -          plane->state->rotation != state->rotation)
 -              return true;
 -
 -      if (plane->state->crtc_w != state->crtc_w)
 +          plane->state->rotation != state->rotation ||
 +          drm_rect_width(&new->src) != drm_rect_width(&cur->src) ||
 +          drm_rect_height(&new->src) != drm_rect_height(&cur->src) ||
 +          drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) ||
 +          drm_rect_height(&new->dst) != drm_rect_height(&cur->dst))
                return true;
  
        return false;
  }
  
 +static bool needs_scaling(struct intel_plane_state *state)
 +{
 +      int src_w = drm_rect_width(&state->src) >> 16;
 +      int src_h = drm_rect_height(&state->src) >> 16;
 +      int dst_w = drm_rect_width(&state->dst);
 +      int dst_h = drm_rect_height(&state->dst);
 +
 +      return (src_w != dst_w || src_h != dst_h);
 +}
 +
  int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
                                    struct drm_plane_state *plane_state)
  {
        bool mode_changed = needs_modeset(crtc_state);
        bool was_crtc_enabled = crtc->state->active;
        bool is_crtc_enabled = crtc_state->active;
 -
        bool turn_off, turn_on, visible, was_visible;
        struct drm_framebuffer *fb = plane_state->fb;
  
                        return ret;
        }
  
 -      /*
 -       * Disabling a plane is always okay; we just need to update
 -       * fb tracking in a special way since cleanup_fb() won't
 -       * get called by the plane helpers.
 -       */
 -      if (old_plane_state->base.fb && !fb)
 -              intel_crtc->atomic.disabled_planes |= 1 << i;
 -
        was_visible = old_plane_state->visible;
        visible = to_intel_plane_state(plane_state)->visible;
  
  
        switch (plane->type) {
        case DRM_PLANE_TYPE_PRIMARY:
 -              intel_crtc->atomic.wait_for_flips = true;
                intel_crtc->atomic.pre_disable_primary = turn_off;
                intel_crtc->atomic.post_enable_primary = turn_on;
  
        case DRM_PLANE_TYPE_CURSOR:
                break;
        case DRM_PLANE_TYPE_OVERLAY:
 -              if (turn_off && !mode_changed) {
 +              /*
 +               * WaCxSRDisabledForSpriteScaling:ivb
 +               *
 +               * cstate->update_wm was already set above, so this flag will
 +               * take effect when we commit and program watermarks.
 +               */
 +              if (IS_IVYBRIDGE(dev) &&
 +                  needs_scaling(to_intel_plane_state(plane_state)) &&
 +                  !needs_scaling(old_plane_state)) {
 +                      to_intel_crtc_state(crtc_state)->disable_lp_wm = true;
 +              } else if (turn_off && !mode_changed) {
                        intel_crtc->atomic.wait_vblank = true;
                        intel_crtc->atomic.update_sprite_watermarks |=
                                1 << i;
                }
 +
 +              break;
        }
        return 0;
  }
@@@ -11897,12 -11813,6 +11917,12 @@@ static int intel_crtc_atomic_check(stru
        }
  
        ret = 0;
 +      if (dev_priv->display.compute_pipe_wm) {
 +              ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
 +              if (ret)
 +                      return ret;
 +      }
 +
        if (INTEL_INFO(dev)->gen >= 9) {
                if (mode_changed)
                        ret = skl_update_scaler_crtc(pipe_config);
@@@ -12092,7 -12002,7 +12112,7 @@@ static void intel_dump_pipe_config(stru
                              pipe_config->dpll_hw_state.pll9,
                              pipe_config->dpll_hw_state.pll10,
                              pipe_config->dpll_hw_state.pcsdw12);
 -      } else if (IS_SKYLAKE(dev)) {
 +      } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: "
                              "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
                              pipe_config->ddi_pll_sel,
                              pipe_config->dpll_hw_state.cfgcr1,
                              pipe_config->dpll_hw_state.cfgcr2);
        } else if (HAS_DDI(dev)) {
-               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x\n",
+               DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
                              pipe_config->ddi_pll_sel,
-                             pipe_config->dpll_hw_state.wrpll);
+                             pipe_config->dpll_hw_state.wrpll,
+                             pipe_config->dpll_hw_state.spll);
        } else {
                DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
                              "fp0: 0x%x, fp1: 0x%x\n",
@@@ -12345,18 -12256,6 +12366,18 @@@ intel_modeset_update_crtc_state(struct 
                        crtc->hwmode = crtc->state->adjusted_mode;
                else
                        crtc->hwmode.crtc_clock = 0;
 +
 +              /*
 +               * Update legacy state to satisfy fbc code. This can
 +               * be removed when fbc uses the atomic state.
 +               */
 +              if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
 +                      struct drm_plane_state *plane_state = crtc->primary->state;
 +
 +                      crtc->primary->fb = plane_state->fb;
 +                      crtc->x = plane_state->src_x >> 16;
 +                      crtc->y = plane_state->src_y >> 16;
 +              }
        }
  }
  
@@@ -12637,6 -12536,7 +12658,7 @@@ intel_pipe_config_compare(struct drm_de
        PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
        PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+       PIPE_CONF_CHECK_X(dpll_hw_state.spll);
        PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
        PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
        PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
@@@ -13120,45 -13020,6 +13142,45 @@@ static int intel_modeset_checks(struct 
        return 0;
  }
  
 +/*
 + * Handle calculation of various watermark data at the end of the atomic check
 + * phase.  The code here should be run after the per-crtc and per-plane 'check'
 + * handlers to ensure that all derived state has been updated.
 + */
 +static void calc_watermark_data(struct drm_atomic_state *state)
 +{
 +      struct drm_device *dev = state->dev;
 +      struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 +      struct drm_crtc *crtc;
 +      struct drm_crtc_state *cstate;
 +      struct drm_plane *plane;
 +      struct drm_plane_state *pstate;
 +
 +      /*
 +       * Calculate watermark configuration details now that derived
 +       * plane/crtc state is all properly updated.
 +       */
 +      drm_for_each_crtc(crtc, dev) {
 +              cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?:
 +                      crtc->state;
 +
 +              if (cstate->active)
 +                      intel_state->wm_config.num_pipes_active++;
 +      }
 +      drm_for_each_legacy_plane(plane, dev) {
 +              pstate = drm_atomic_get_existing_plane_state(state, plane) ?:
 +                      plane->state;
 +
 +              if (!to_intel_plane_state(pstate)->visible)
 +                      continue;
 +
 +              intel_state->wm_config.sprites_enabled = true;
 +              if (pstate->crtc_w != pstate->src_w >> 16 ||
 +                  pstate->crtc_h != pstate->src_h >> 16)
 +                      intel_state->wm_config.sprites_scaled = true;
 +      }
 +}
 +
  /**
   * intel_atomic_check - validate state object
   * @dev: drm device
  static int intel_atomic_check(struct drm_device *dev,
                              struct drm_atomic_state *state)
  {
 +      struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
        int ret, i;
                struct intel_crtc_state *pipe_config =
                        to_intel_crtc_state(crtc_state);
  
+               memset(&to_intel_crtc(crtc)->atomic, 0,
+                      sizeof(struct intel_crtc_atomic_commit));
                /* Catch I915_MODE_FLAG_INHERITED */
                if (crtc_state->mode.private_flags != crtc->state->mode.private_flags)
                        crtc_state->mode_changed = true;
                if (ret)
                        return ret;
  
-               if (intel_pipe_config_compare(state->dev,
+               if (i915.fastboot &&
+                   intel_pipe_config_compare(state->dev,
                                        to_intel_crtc_state(crtc->state),
                                        pipe_config, true)) {
                        crtc_state->mode_changed = false;
                if (ret)
                        return ret;
        } else
 -              to_intel_atomic_state(state)->cdclk =
 -                      to_i915(state->dev)->cdclk_freq;
 +              intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
  
 -      return drm_atomic_helper_check_planes(state->dev, state);
 +      ret = drm_atomic_helper_check_planes(state->dev, state);
 +      if (ret)
 +              return ret;
 +
 +      calc_watermark_data(state);
 +
 +      return 0;
 +}
 +
 +static int intel_atomic_prepare_commit(struct drm_device *dev,
 +                                     struct drm_atomic_state *state,
 +                                     bool async)
 +{
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_plane_state *plane_state;
 +      struct drm_crtc_state *crtc_state;
 +      struct drm_plane *plane;
 +      struct drm_crtc *crtc;
 +      int i, ret;
 +
 +      if (async) {
 +              DRM_DEBUG_KMS("i915 does not yet support async commit\n");
 +              return -EINVAL;
 +      }
 +
 +      for_each_crtc_in_state(state, crtc, crtc_state, i) {
 +              ret = intel_crtc_wait_for_pending_flips(crtc);
 +              if (ret)
 +                      return ret;
 +
 +              if (atomic_read(&to_intel_crtc(crtc)->unpin_work_count) >= 2)
 +                      flush_workqueue(dev_priv->wq);
 +      }
 +
 +      ret = mutex_lock_interruptible(&dev->struct_mutex);
 +      if (ret)
 +              return ret;
 +
 +      ret = drm_atomic_helper_prepare_planes(dev, state);
 +      if (!ret && !async && !i915_reset_in_progress(&dev_priv->gpu_error)) {
 +              u32 reset_counter;
 +
 +              reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 +              mutex_unlock(&dev->struct_mutex);
 +
 +              for_each_plane_in_state(state, plane, plane_state, i) {
 +                      struct intel_plane_state *intel_plane_state =
 +                              to_intel_plane_state(plane_state);
 +
 +                      if (!intel_plane_state->wait_req)
 +                              continue;
 +
 +                      ret = __i915_wait_request(intel_plane_state->wait_req,
 +                                                reset_counter, true,
 +                                                NULL, NULL);
 +
 +                      /* Swallow -EIO errors to allow updates during hw lockup. */
 +                      if (ret == -EIO)
 +                              ret = 0;
 +
 +                      if (ret)
 +                              break;
 +              }
 +
 +              if (!ret)
 +                      return 0;
 +
 +              mutex_lock(&dev->struct_mutex);
 +              drm_atomic_helper_cleanup_planes(dev, state);
 +      }
 +
 +      mutex_unlock(&dev->struct_mutex);
 +      return ret;
  }
  
  /**
@@@ -13329,20 -13122,22 +13355,20 @@@ static int intel_atomic_commit(struct d
                               bool async)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
 +      struct drm_crtc *crtc;
        int ret = 0;
        int i;
        bool any_ms = false;
  
 -      if (async) {
 -              DRM_DEBUG_KMS("i915 does not yet support async commit\n");
 -              return -EINVAL;
 -      }
 -
 -      ret = drm_atomic_helper_prepare_planes(dev, state);
 -      if (ret)
 +      ret = intel_atomic_prepare_commit(dev, state, async);
 +      if (ret) {
 +              DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret);
                return ret;
 +      }
  
        drm_atomic_helper_swap_state(dev, state);
 +      dev_priv->wm.config = to_intel_atomic_state(state)->wm_config;
  
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
                        to_intel_crtc_state(crtc->state)->update_pipe;
                unsigned long put_domains = 0;
  
 +              if (modeset)
 +                      intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
 +
                if (modeset && crtc->state->active) {
                        update_scanline_offset(to_intel_crtc(crtc));
                        dev_priv->display.crtc_enable(crtc);
                if (!modeset)
                        intel_pre_plane_update(intel_crtc);
  
 -              drm_atomic_helper_commit_planes_on_crtc(crtc_state);
 +              if (crtc->state->active &&
 +                  (crtc->state->planes_changed || update_pipe))
 +                      drm_atomic_helper_commit_planes_on_crtc(crtc_state);
  
                if (put_domains)
                        modeset_put_power_domains(dev_priv, put_domains);
  
                intel_post_plane_update(intel_crtc);
 +
 +              if (modeset)
 +                      intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
        }
  
        /* FIXME: add subpixel order */
  
        drm_atomic_helper_wait_for_vblanks(dev, state);
 +
 +      mutex_lock(&dev->struct_mutex);
        drm_atomic_helper_cleanup_planes(dev, state);
 +      mutex_unlock(&dev->struct_mutex);
  
        if (any_ms)
                intel_modeset_check_state(dev, state);
@@@ -13586,8 -13370,6 +13612,8 @@@ static void intel_shared_dpll_init(stru
   * bits.  Some older platforms need special physical address handling for
   * cursor planes.
   *
 + * Must be called with struct_mutex held.
 + *
   * Returns 0 on success, negative error code on failure.
   */
  int
@@@ -13598,58 -13380,28 +13624,58 @@@ intel_prepare_plane_fb(struct drm_plan
        struct drm_framebuffer *fb = new_state->fb;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
 +      struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb);
        int ret = 0;
  
 -      if (!obj)
 +      if (!obj && !old_obj)
                return 0;
  
 -      mutex_lock(&dev->struct_mutex);
 +      if (old_obj) {
 +              struct drm_crtc_state *crtc_state =
 +                      drm_atomic_get_existing_crtc_state(new_state->state, plane->state->crtc);
 +
 +              /* 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.
 +               */
 +              if (needs_modeset(crtc_state))
 +                      ret = i915_gem_object_wait_rendering(old_obj, true);
  
 -      if (plane->type == DRM_PLANE_TYPE_CURSOR &&
 +              /* Swallow -EIO errors to allow updates during hw lockup. */
 +              if (ret && ret != -EIO)
 +                      return ret;
 +      }
 +
 +      if (!obj) {
 +              ret = 0;
 +      } else if (plane->type == DRM_PLANE_TYPE_CURSOR &&
            INTEL_INFO(dev)->cursor_needs_physical) {
                int align = IS_I830(dev) ? 16 * 1024 : 256;
                ret = i915_gem_object_attach_phys(obj, align);
                if (ret)
                        DRM_DEBUG_KMS("failed to attach phys object\n");
        } else {
 -              ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL, NULL);
 +              ret = intel_pin_and_fence_fb_obj(plane, fb, new_state);
        }
  
 -      if (ret == 0)
 -              i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
 +      if (ret == 0) {
 +              if (obj) {
 +                      struct intel_plane_state *plane_state =
 +                              to_intel_plane_state(new_state);
  
 -      mutex_unlock(&dev->struct_mutex);
 +                      i915_gem_request_assign(&plane_state->wait_req,
 +                                              obj->last_write_req);
 +              }
 +
 +              i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
 +      }
  
        return ret;
  }
   * @fb: old framebuffer that was on plane
   *
   * Cleans up a framebuffer that has just been removed from a plane.
 + *
 + * Must be called with struct_mutex held.
   */
  void
  intel_cleanup_plane_fb(struct drm_plane *plane,
                       const struct drm_plane_state *old_state)
  {
        struct drm_device *dev = plane->dev;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(old_state->fb);
 +      struct intel_plane *intel_plane = to_intel_plane(plane);
 +      struct intel_plane_state *old_intel_state;
 +      struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb);
 +      struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb);
  
 -      if (!obj)
 +      old_intel_state = to_intel_plane_state(old_state);
 +
 +      if (!obj && !old_obj)
                return;
  
 -      if (plane->type != DRM_PLANE_TYPE_CURSOR ||
 -          !INTEL_INFO(dev)->cursor_needs_physical) {
 -              mutex_lock(&dev->struct_mutex);
 +      if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
 +          !INTEL_INFO(dev)->cursor_needs_physical))
                intel_unpin_fb_obj(old_state->fb, old_state);
 -              mutex_unlock(&dev->struct_mutex);
 -      }
 +
 +      /* prepare_fb aborted? */
 +      if ((old_obj && (old_obj->frontbuffer_bits & intel_plane->frontbuffer_bit)) ||
 +          (obj && !(obj->frontbuffer_bits & intel_plane->frontbuffer_bit)))
 +              i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
 +
 +      i915_gem_request_assign(&old_intel_state->wait_req, NULL);
 +
  }
  
  int
@@@ -13707,7 -13447,7 +13733,7 @@@ skl_max_scale(struct intel_crtc *intel_
        crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
        cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk;
  
 -      if (!crtc_clock || !cdclk)
 +      if (WARN_ON_ONCE(!crtc_clock || cdclk < crtc_clock))
                return DRM_PLANE_HELPER_NO_SCALING;
  
        /*
@@@ -13755,8 -13495,18 +13781,8 @@@ intel_commit_primary_plane(struct drm_p
        struct drm_framebuffer *fb = state->base.fb;
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_crtc *intel_crtc;
 -      struct drm_rect *src = &state->src;
  
        crtc = crtc ? crtc : plane->crtc;
 -      intel_crtc = to_intel_crtc(crtc);
 -
 -      plane->fb = fb;
 -      crtc->x = src->x1 >> 16;
 -      crtc->y = src->y1 >> 16;
 -
 -      if (!crtc->state->active)
 -              return;
  
        dev_priv->display.update_primary_plane(crtc, fb,
                                               state->src.x1 >> 16,
@@@ -13786,7 -13536,8 +13812,7 @@@ static void intel_begin_crtc_commit(str
                intel_update_watermarks(crtc);
  
        /* Perform vblank evasion around commit operation */
 -      if (crtc->state->active)
 -              intel_pipe_update_start(intel_crtc);
 +      intel_pipe_update_start(intel_crtc);
  
        if (modeset)
                return;
@@@ -13802,7 -13553,8 +13828,7 @@@ static void intel_finish_crtc_commit(st
  {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  
 -      if (crtc->state->active)
 -              intel_pipe_update_end(intel_crtc);
 +      intel_pipe_update_end(intel_crtc);
  }
  
  /**
@@@ -13985,7 -13737,8 +14011,7 @@@ intel_commit_cursor_plane(struct drm_pl
        intel_crtc->cursor_bo = obj;
  
  update:
 -      if (crtc->state->active)
 -              intel_crtc_update_cursor(crtc, state->visible);
 +      intel_crtc_update_cursor(crtc, state->visible);
  }
  
  static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
@@@ -14257,7 -14010,7 +14283,7 @@@ static void intel_setup_outputs(struct 
                 */
                found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED;
                /* WaIgnoreDDIAStrap: skl */
 -              if (found || IS_SKYLAKE(dev))
 +              if (found || IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                        intel_ddi_init(dev, PORT_A);
  
                /* DDI B, C and D detection is indicated by the SFUSE_STRAP
                /*
                 * On SKL we don't have a way to detect DDI-E so we rely on VBT.
                 */
 -              if (IS_SKYLAKE(dev) &&
 +              if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) &&
                    (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))
  
                if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) {
                        /* PCH SDVOB multiplex with HDMIB */
 -                      found = intel_sdvo_init(dev, PCH_SDVOB, true);
 +                      found = intel_sdvo_init(dev, PCH_SDVOB, PORT_B);
                        if (!found)
                                intel_hdmi_init(dev, PCH_HDMIB, PORT_B);
                        if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
  
                if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
                        DRM_DEBUG_KMS("probing SDVOB\n");
 -                      found = intel_sdvo_init(dev, GEN3_SDVOB, true);
 +                      found = intel_sdvo_init(dev, GEN3_SDVOB, PORT_B);
                        if (!found && IS_G4X(dev)) {
                                DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
                                intel_hdmi_init(dev, GEN4_HDMIB, PORT_B);
  
                if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) {
                        DRM_DEBUG_KMS("probing SDVOC\n");
 -                      found = intel_sdvo_init(dev, GEN3_SDVOC, false);
 +                      found = intel_sdvo_init(dev, GEN3_SDVOC, PORT_C);
                }
  
                if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) {
@@@ -14413,6 -14166,11 +14439,11 @@@ static int intel_user_framebuffer_creat
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
  
+       if (obj->userptr.mm) {
+               DRM_DEBUG("attempting to use a userptr for a framebuffer, denied\n");
+               return -EINVAL;
+       }
        return drm_gem_handle_create(file, &obj->base, handle);
  }
  
@@@ -14619,21 -14377,17 +14650,22 @@@ static int intel_framebuffer_init(struc
  static struct drm_framebuffer *
  intel_user_framebuffer_create(struct drm_device *dev,
                              struct drm_file *filp,
-                             struct drm_mode_fb_cmd2 *mode_cmd)
+                             struct drm_mode_fb_cmd2 *user_mode_cmd)
  {
 +      struct drm_framebuffer *fb;
        struct drm_i915_gem_object *obj;
+       struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
  
        obj = to_intel_bo(drm_gem_object_lookup(dev, filp,
-                                               mode_cmd->handles[0]));
+                                               mode_cmd.handles[0]));
        if (&obj->base == NULL)
                return ERR_PTR(-ENOENT);
  
-       fb = intel_framebuffer_create(dev, mode_cmd, obj);
 -      return intel_framebuffer_create(dev, &mode_cmd, obj);
++      fb = intel_framebuffer_create(dev, &mode_cmd, obj);
 +      if (IS_ERR(fb))
 +              drm_gem_object_unreference_unlocked(&obj->base);
 +
 +      return fb;
  }
  
  #ifndef CONFIG_DRM_FBDEV_EMULATION
@@@ -14718,7 -14472,7 +14750,7 @@@ static void intel_init_display(struct d
        }
  
        /* Returns the core display clock speed */
 -      if (IS_SKYLAKE(dev))
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                dev_priv->display.get_display_clock_speed =
                        skylake_get_display_clock_speed;
        else if (IS_BROXTON(dev))
@@@ -14965,6 -14719,9 +14997,9 @@@ static struct intel_quirk intel_quirks[
        /* Apple Macbook 2,1 (Core 2 T7400) */
        { 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
  
+       /* Apple Macbook 4,1 */
+       { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present },
        /* Toshiba CB35 Chromebook (Celeron 2955U) */
        { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
  
  
        /* Dell Chromebook 11 */
        { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
+       /* Dell Chromebook 11 (2015 version) */
+       { 0x0a16, 0x1028, 0x0a35, quirk_backlight_present },
  };
  
  static void intel_init_quirks(struct drm_device *dev)
@@@ -15001,7 -14761,7 +15039,7 @@@ static void i915_disable_vga(struct drm
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u8 sr1;
 -      u32 vga_reg = i915_vgacntrl_reg(dev);
 +      i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
  
        /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
        vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
@@@ -15117,6 -14877,9 +15155,6 @@@ void intel_modeset_init(struct drm_devi
        i915_disable_vga(dev);
        intel_setup_outputs(dev);
  
 -      /* Just in case the BIOS is doing something questionable. */
 -      intel_fbc_disable(dev_priv);
 -
        drm_modeset_lock_all(dev);
        intel_modeset_setup_hw_state(dev);
        drm_modeset_unlock_all(dev);
@@@ -15203,9 -14966,10 +15241,9 @@@ static void intel_sanitize_crtc(struct 
  {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 reg;
 +      i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder);
  
        /* Clear any frame start delays used for debugging left by the BIOS */
 -      reg = PIPECONF(crtc->config->cpu_transcoder);
        I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
  
        /* restore vblank interrupts to correct state */
@@@ -15359,7 -15123,7 +15397,7 @@@ static void intel_sanitize_encoder(stru
  void i915_redisable_vga_power_on(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 vga_reg = i915_vgacntrl_reg(dev);
 +      i915_reg_t vga_reg = i915_vgacntrl_reg(dev);
  
        if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
                DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
@@@ -15398,7 -15162,7 +15436,7 @@@ static void readout_plane_state(struct 
        struct intel_plane_state *plane_state =
                to_intel_plane_state(primary->state);
  
 -      plane_state->visible =
 +      plane_state->visible = crtc->active &&
                primary_get_hw_state(to_intel_plane(primary));
  
        if (plane_state->visible)
@@@ -15655,7 -15419,8 +15693,7 @@@ void intel_modeset_gem_init(struct drm_
                mutex_lock(&dev->struct_mutex);
                ret = intel_pin_and_fence_fb_obj(c->primary,
                                                 c->primary->fb,
 -                                               c->primary->state,
 -                                               NULL, NULL);
 +                                               c->primary->state);
                mutex_unlock(&dev->struct_mutex);
                if (ret) {
                        DRM_ERROR("failed to pin boot fb on pipe %d\n",
@@@ -173,14 -173,20 +173,14 @@@ static void intel_mst_pre_enable_dp(str
        intel_mst->port = found->port;
  
        if (intel_dp->active_mst_links == 0) {
 -              enum port port = intel_ddi_get_encoder_port(encoder);
 +              intel_ddi_clk_select(encoder, intel_crtc->config);
  
                intel_dp_set_link_params(intel_dp, intel_crtc->config);
  
 -              /* FIXME: add support for SKL */
 -              if (INTEL_INFO(dev)->gen < 9)
 -                      I915_WRITE(PORT_CLK_SEL(port),
 -                                 intel_crtc->config->ddi_pll_sel);
 -
                intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
  
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
  
 -
                intel_dp_start_link_train(intel_dp);
                intel_dp_stop_link_train(intel_dp);
        }
@@@ -408,10 -414,7 +408,10 @@@ static void intel_connector_add_to_fbde
  {
  #ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 -      drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, &connector->base);
 +
 +      if (dev_priv->fbdev)
 +              drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper,
 +                                              &connector->base);
  #endif
  }
  
@@@ -419,10 -422,7 +419,10 @@@ static void intel_connector_remove_from
  {
  #ifdef CONFIG_DRM_FBDEV_EMULATION
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 -      drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, &connector->base);
 +
 +      if (dev_priv->fbdev)
 +              drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper,
 +                                                 &connector->base);
  #endif
  }
  
@@@ -458,11 -458,17 +458,17 @@@ static struct drm_connector *intel_dp_a
        drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
  
        drm_mode_connector_set_path_property(connector, pathprop);
+       return connector;
+ }
+ static void intel_dp_register_mst_connector(struct drm_connector *connector)
+ {
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct drm_device *dev = connector->dev;
        drm_modeset_lock_all(dev);
        intel_connector_add_to_fbdev(intel_connector);
        drm_modeset_unlock_all(dev);
        drm_connector_register(&intel_connector->base);
-       return connector;
  }
  
  static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
@@@ -508,6 -514,7 +514,7 @@@ static void intel_dp_mst_hotplug(struc
  
  static struct drm_dp_mst_topology_cbs mst_cbs = {
        .add_connector = intel_dp_add_mst_connector,
+       .register_connector = intel_dp_register_mst_connector,
        .destroy_connector = intel_dp_destroy_mst_connector,
        .hotplug = intel_dp_mst_hotplug,
  };
@@@ -31,7 -31,7 +31,7 @@@
  #include "intel_guc.h"
  
  /**
 - * DOC: GuC
 + * DOC: GuC-specific firmware loader
   *
   * intel_guc:
   * Top level structure of guc. It handles firmware loading and manages client
@@@ -208,6 -208,16 +208,6 @@@ static inline bool guc_ucode_response(s
  /*
   * Transfer the firmware image to RAM for execution by the microcontroller.
   *
 - * GuC Firmware layout:
 - * +-------------------------------+  ----
 - * |          CSS header           |  128B
 - * | contains major/minor version  |
 - * +-------------------------------+  ----
 - * |             uCode             |
 - * +-------------------------------+  ----
 - * |         RSA signature         |  256B
 - * +-------------------------------+  ----
 - *
   * Architecturally, the DMA engine is bidirectional, and can potentially even
   * transfer between GTT locations. This functionality is left out of the API
   * for now as there is no need for it.
   * Note that GuC needs the CSS header plus uKernel code to be copied by the
   * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
   */
 -
 -#define UOS_CSS_HEADER_OFFSET         0
 -#define UOS_VER_MINOR_OFFSET          0x44
 -#define UOS_VER_MAJOR_OFFSET          0x46
 -#define UOS_CSS_HEADER_SIZE           0x80
 -#define UOS_RSA_SIG_SIZE              0x100
 -
  static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
  {
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
        struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
        unsigned long offset;
        struct sg_table *sg = fw_obj->pages;
 -      u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
 +      u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
        int i, ret = 0;
  
 -      /* uCode size, also is where RSA signature starts */
 -      offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
 -      I915_WRITE(DMA_COPY_SIZE, ucode_size);
 +      /* where RSA signature starts */
 +      offset = guc_fw->rsa_offset;
  
        /* Copy RSA signature from the fw image to HW for verification */
 -      sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
 -      for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
 +      sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset);
 +      for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++)
                I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
  
 +      /* The header plus uCode will be copied to WOPCM via DMA, excluding any
 +       * other components */
 +      I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
 +
        /* Set the source address for the new blob */
 -      offset = i915_gem_obj_ggtt_offset(fw_obj);
 +      offset = i915_gem_obj_ggtt_offset(fw_obj) + guc_fw->header_offset;
        I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
        I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
  
@@@ -308,8 -322,8 +308,8 @@@ static int guc_ucode_xfer(struct drm_i9
        I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
  
        /* WaDisableMinuteIaClockGating:skl,bxt */
 -      if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) {
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) &
                                              ~GUC_ENABLE_MIA_CLOCK_GATING));
        }
@@@ -364,9 -378,6 +364,9 @@@ int intel_guc_ucode_load(struct drm_dev
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
        int err = 0;
  
 +      if (!i915.enable_guc_submission)
 +              return 0;
 +
        DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
                intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
                intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
@@@ -446,8 -457,10 +446,8 @@@ static void guc_fw_fetch(struct drm_dev
  {
        struct drm_i915_gem_object *obj;
        const struct firmware *fw;
 -      const u8 *css_header;
 -      const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
 -      const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
 -                      - 0x8000; /* 32k reserved (8K stack + 24k context) */
 +      struct guc_css_header *css;
 +      size_t size;
        int err;
  
        DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
  
        DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
                guc_fw->guc_fw_path, fw);
 -      DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
 -              fw->size, minsize, maxsize);
  
 -      /* Check the size of the blob befoe examining buffer contents */
 -      if (fw->size < minsize || fw->size > maxsize)
 +      /* Check the size of the blob before examining buffer contents */
 +      if (fw->size < sizeof(struct guc_css_header)) {
 +              DRM_ERROR("Firmware header is missing\n");
 +              goto fail;
 +      }
 +
 +      css = (struct guc_css_header *)fw->data;
 +
 +      /* Firmware bits always start from header */
 +      guc_fw->header_offset = 0;
 +      guc_fw->header_size = (css->header_size_dw - css->modulus_size_dw -
 +              css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
 +
 +      if (guc_fw->header_size != sizeof(struct guc_css_header)) {
 +              DRM_ERROR("CSS header definition mismatch\n");
 +              goto fail;
 +      }
 +
 +      /* then, uCode */
 +      guc_fw->ucode_offset = guc_fw->header_offset + guc_fw->header_size;
 +      guc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
 +
 +      /* now RSA */
 +      if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
 +              DRM_ERROR("RSA key size is bad\n");
 +              goto fail;
 +      }
 +      guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
 +      guc_fw->rsa_size = css->key_size_dw * sizeof(u32);
 +
 +      /* At least, it should have header, uCode and RSA. Size of all three. */
 +      size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size;
 +      if (fw->size < size) {
 +              DRM_ERROR("Missing firmware components\n");
                goto fail;
 +      }
 +
 +      /* Header and uCode will be loaded to WOPCM. Size of the two. */
 +      size = guc_fw->header_size + guc_fw->ucode_size;
 +
 +      /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
 +      if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
 +              DRM_ERROR("Firmware is too large to fit in WOPCM\n");
 +              goto fail;
 +      }
  
        /*
         * The GuC firmware image has the version number embedded at a well-known
         * TWO bytes each (i.e. u16), although all pointers and offsets are defined
         * in terms of bytes (u8).
         */
 -      css_header = fw->data + UOS_CSS_HEADER_OFFSET;
 -      guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
 -      guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
 +      guc_fw->guc_fw_major_found = css->guc_sw_version >> 16;
 +      guc_fw->guc_fw_minor_found = css->guc_sw_version & 0xFFFF;
  
        if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
            guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
                        guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
                        guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
  
+       mutex_lock(&dev->struct_mutex);
        obj = i915_gem_object_create_from_data(dev, fw->data, fw->size);
+       mutex_unlock(&dev->struct_mutex);
        if (IS_ERR_OR_NULL(obj)) {
                err = obj ? PTR_ERR(obj) : -ENOMEM;
                goto fail;
@@@ -566,8 -542,6 +568,6 @@@ fail
   * @dev:      drm device
   *
   * Called early during driver load, but after GEM is initialised.
-  * The device struct_mutex must be held by the caller, as we're
-  * going to allocate a GEM object to hold the firmware image.
   *
   * The firmware will be transferred to the GuC's memory later,
   * when intel_guc_ucode_load() is called.
@@@ -592,9 -566,6 +592,9 @@@ void intel_guc_ucode_init(struct drm_de
                fw_path = "";   /* unknown device */
        }
  
 +      if (!i915.enable_guc_submission)
 +              return;
 +
        guc_fw->guc_dev = dev;
        guc_fw->guc_fw_path = fw_path;
        guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
@@@ -627,9 -598,11 +627,11 @@@ void intel_guc_ucode_fini(struct drm_de
        direct_interrupts_to_host(dev_priv);
        i915_guc_submission_fini(dev);
  
+       mutex_lock(&dev->struct_mutex);
        if (guc_fw->guc_fw_obj)
                drm_gem_object_unreference(&guc_fw->guc_fw_obj->base);
        guc_fw->guc_fw_obj = NULL;
+       mutex_unlock(&dev->struct_mutex);
  
        guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
  }
  #define GEN8_CTX_L3LLC_COHERENT (1<<5)
  #define GEN8_CTX_PRIVILEGE (1<<8)
  
 -#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \
 +#define ASSIGN_CTX_REG(reg_state, pos, reg, val) do { \
 +      (reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \
 +      (reg_state)[(pos)+1] = (val); \
 +} while (0)
 +
 +#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do {              \
        const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \
        reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \
        reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
 -}
 +} while (0)
  
 -#define ASSIGN_CTX_PML4(ppgtt, reg_state) { \
 +#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \
        reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \
        reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \
 -}
 +} while (0)
  
  enum {
        ADVANCED_CONTEXT = 0,
@@@ -289,8 -284,8 +289,8 @@@ static bool disable_lite_restore_wa(str
  {
        struct drm_device *dev = ring->dev;
  
 -      return ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
 -              (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) &&
 +      return (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
 +              IS_BXT_REVID(dev, 0, BXT_REVID_A1)) &&
               (ring->id == VCS || ring->id == VCS2);
  }
  
@@@ -516,16 -511,16 +516,16 @@@ void intel_lrc_irq_handler(struct intel
        status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
  
        read_pointer = ring->next_context_status_buffer;
-       write_pointer = status_pointer & 0x07;
+       write_pointer = status_pointer & GEN8_CSB_PTR_MASK;
        if (read_pointer > write_pointer)
-               write_pointer += 6;
+               write_pointer += GEN8_CSB_ENTRIES;
  
        spin_lock(&ring->execlist_lock);
  
        while (read_pointer < write_pointer) {
                read_pointer++;
-               status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % 6));
-               status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % 6));
+               status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES));
+               status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES));
  
                if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
                        continue;
        spin_unlock(&ring->execlist_lock);
  
        WARN(submit_contexts > 2, "More than two context complete events?\n");
-       ring->next_context_status_buffer = write_pointer % 6;
+       ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES;
  
        I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
-                  _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8));
+                  _MASKED_FIELD(GEN8_CSB_PTR_MASK << 8,
+                                ((u32)ring->next_context_status_buffer &
+                                 GEN8_CSB_PTR_MASK) << 8));
  }
  
  static int execlists_context_queue(struct drm_i915_gem_request *request)
@@@ -924,7 -921,7 +926,7 @@@ int intel_execlists_submission(struct i
  
                intel_logical_ring_emit(ringbuf, MI_NOOP);
                intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
 -              intel_logical_ring_emit(ringbuf, INSTPM);
 +              intel_logical_ring_emit_reg(ringbuf, INSTPM);
                intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
                intel_logical_ring_advance(ringbuf);
  
@@@ -1099,7 -1096,7 +1101,7 @@@ static int intel_logical_ring_workaroun
  
        intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(w->count));
        for (i = 0; i < w->count; i++) {
 -              intel_logical_ring_emit(ringbuf, w->reg[i].addr);
 +              intel_logical_ring_emit_reg(ringbuf, w->reg[i].addr);
                intel_logical_ring_emit(ringbuf, w->reg[i].value);
        }
        intel_logical_ring_emit(ringbuf, MI_NOOP);
                batch[__index] = (cmd);                                 \
        } while (0)
  
 +#define wa_ctx_emit_reg(batch, index, reg) \
 +      wa_ctx_emit((batch), (index), i915_mmio_reg_offset(reg))
  
  /*
   * In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after
@@@ -1154,17 -1149,17 +1156,17 @@@ static inline int gen8_emit_flush_coher
         * this batch updates GEN8_L3SQCREG4 with default value we need to
         * set this bit here to retain the WA during flush.
         */
 -      if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0)
 +      if (IS_SKL_REVID(ring->dev, 0, SKL_REVID_E0))
                l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS;
  
        wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
                                   MI_SRM_LRM_GLOBAL_GTT));
 -      wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
 +      wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
        wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
        wa_ctx_emit(batch, index, 0);
  
        wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
 -      wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
 +      wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
        wa_ctx_emit(batch, index, l3sqc4_flush);
  
        wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6));
  
        wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 |
                                   MI_SRM_LRM_GLOBAL_GTT));
 -      wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
 +      wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
        wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
        wa_ctx_emit(batch, index, 0);
  
@@@ -1319,8 -1314,8 +1321,8 @@@ static int gen9_init_indirectctx_bb(str
        uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
  
        /* WaDisableCtxRestoreArbitration:skl,bxt */
 -      if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) ||
 -          (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0)))
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE);
  
        /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */
@@@ -1345,18 -1340,18 +1347,18 @@@ static int gen9_init_perctx_bb(struct i
        uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS);
  
        /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
 -      if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_B0)) ||
 -          (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) {
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1));
 -              wa_ctx_emit(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0);
 +              wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0);
                wa_ctx_emit(batch, index,
                            _MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING));
                wa_ctx_emit(batch, index, MI_NOOP);
        }
  
        /* WaDisableCtxRestoreArbitration:skl,bxt */
 -      if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) ||
 -          (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0)))
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE);
  
        wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END);
@@@ -1469,6 -1464,7 +1471,7 @@@ static int gen8_init_common_ring(struc
  {
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u8 next_context_status_buffer_hw;
  
        lrc_setup_hardware_status_page(ring,
                                ring->default_context->engine[ring->id].state);
        I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
        I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
  
 -      if (ring->status_page.obj) {
 -              I915_WRITE(RING_HWS_PGA(ring->mmio_base),
 -                         (u32)ring->status_page.gfx_addr);
 -              POSTING_READ(RING_HWS_PGA(ring->mmio_base));
 -      }
 -
        I915_WRITE(RING_MODE_GEN7(ring),
                   _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
                   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
        POSTING_READ(RING_MODE_GEN7(ring));
-       ring->next_context_status_buffer = 0;
+       /*
+        * Instead of resetting the Context Status Buffer (CSB) read pointer to
+        * zero, we need to read the write pointer from hardware and use its
+        * value because "this register is power context save restored".
+        * Effectively, these states have been observed:
+        *
+        *      | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) |
+        * BDW  | CSB regs not reset       | CSB regs reset       |
+        * CHT  | CSB regs not reset       | CSB regs not reset   |
+        */
+       next_context_status_buffer_hw = (I915_READ(RING_CONTEXT_STATUS_PTR(ring))
+                                                  & GEN8_CSB_PTR_MASK);
+       /*
+        * When the CSB registers are reset (also after power-up / gpu reset),
+        * CSB write pointer is set to all 1's, which is not valid, use '5' in
+        * this special case, so the first element read is CSB[0].
+        */
+       if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK)
+               next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1);
+       ring->next_context_status_buffer = next_context_status_buffer_hw;
        DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
  
        memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
@@@ -1538,9 -1562,9 +1563,9 @@@ static int intel_logical_ring_emit_pdps
        for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) {
                const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
  
 -              intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_UDW(ring, i));
 +              intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_UDW(ring, i));
                intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr));
 -              intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_LDW(ring, i));
 +              intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_LDW(ring, i));
                intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr));
        }
  
@@@ -1682,6 -1706,7 +1707,7 @@@ static int gen8_emit_flush_render(struc
        if (flush_domains) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
  
        if (invalidate_domains) {
@@@ -1898,7 -1923,6 +1924,7 @@@ static int logical_ring_init(struct drm
        i915_gem_batch_pool_init(dev, &ring->batch_pool);
        init_waitqueue_head(&ring->irq_queue);
  
 +      INIT_LIST_HEAD(&ring->buffers);
        INIT_LIST_HEAD(&ring->execlist_queue);
        INIT_LIST_HEAD(&ring->execlist_retired_req_list);
        spin_lock_init(&ring->execlist_lock);
@@@ -1948,7 -1972,7 +1974,7 @@@ static int logical_render_ring_init(str
                ring->init_hw = gen8_init_render_ring;
        ring->init_context = gen8_init_rcs_context;
        ring->cleanup = intel_fini_pipe_control;
 -      if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                ring->get_seqno = bxt_a_get_seqno;
                ring->set_seqno = bxt_a_set_seqno;
        } else {
@@@ -2000,7 -2024,7 +2026,7 @@@ static int logical_bsd_ring_init(struc
                GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
  
        ring->init_hw = gen8_init_common_ring;
 -      if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                ring->get_seqno = bxt_a_get_seqno;
                ring->set_seqno = bxt_a_set_seqno;
        } else {
@@@ -2055,7 -2079,7 +2081,7 @@@ static int logical_blt_ring_init(struc
                GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
  
        ring->init_hw = gen8_init_common_ring;
 -      if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                ring->get_seqno = bxt_a_get_seqno;
                ring->set_seqno = bxt_a_set_seqno;
        } else {
@@@ -2085,7 -2109,7 +2111,7 @@@ static int logical_vebox_ring_init(stru
                GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
  
        ring->init_hw = gen8_init_common_ring;
 -      if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                ring->get_seqno = bxt_a_get_seqno;
                ring->set_seqno = bxt_a_set_seqno;
        } else {
@@@ -2239,31 -2263,46 +2265,31 @@@ populate_lr_context(struct intel_contex
         * only for the first context restore: on a subsequent save, the GPU will
         * recreate this batchbuffer with new values (including all the missing
         * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */
 -      if (ring->id == RCS)
 -              reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14);
 -      else
 -              reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11);
 -      reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED;
 -      reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring);
 -      reg_state[CTX_CONTEXT_CONTROL+1] =
 -              _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
 -                                 CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
 -                                 CTX_CTRL_RS_CTX_ENABLE);
 -      reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base);
 -      reg_state[CTX_RING_HEAD+1] = 0;
 -      reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);
 -      reg_state[CTX_RING_TAIL+1] = 0;
 -      reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base);
 +      reg_state[CTX_LRI_HEADER_0] =
 +              MI_LOAD_REGISTER_IMM(ring->id == RCS ? 14 : 11) | MI_LRI_FORCE_POSTED;
 +      ASSIGN_CTX_REG(reg_state, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(ring),
 +                     _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
 +                                        CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
 +                                        CTX_CTRL_RS_CTX_ENABLE));
 +      ASSIGN_CTX_REG(reg_state, CTX_RING_HEAD, RING_HEAD(ring->mmio_base), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_RING_TAIL, RING_TAIL(ring->mmio_base), 0);
        /* Ring buffer start address is not known until the buffer is pinned.
         * It is written to the context image in execlists_update_context()
         */
 -      reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base);
 -      reg_state[CTX_RING_BUFFER_CONTROL+1] =
 -                      ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID;
 -      reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168;
 -      reg_state[CTX_BB_HEAD_U+1] = 0;
 -      reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140;
 -      reg_state[CTX_BB_HEAD_L+1] = 0;
 -      reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110;
 -      reg_state[CTX_BB_STATE+1] = (1<<5);
 -      reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c;
 -      reg_state[CTX_SECOND_BB_HEAD_U+1] = 0;
 -      reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114;
 -      reg_state[CTX_SECOND_BB_HEAD_L+1] = 0;
 -      reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118;
 -      reg_state[CTX_SECOND_BB_STATE+1] = 0;
 +      ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_START, RING_START(ring->mmio_base), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_CONTROL, RING_CTL(ring->mmio_base),
 +                     ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID);
 +      ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_U, RING_BBADDR_UDW(ring->mmio_base), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_L, RING_BBADDR(ring->mmio_base), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_BB_STATE, RING_BBSTATE(ring->mmio_base),
 +                     RING_BB_PPGTT);
 +      ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_U, RING_SBBADDR_UDW(ring->mmio_base), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_L, RING_SBBADDR(ring->mmio_base), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_STATE, RING_SBBSTATE(ring->mmio_base), 0);
        if (ring->id == RCS) {
 -              reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0;
 -              reg_state[CTX_BB_PER_CTX_PTR+1] = 0;
 -              reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4;
 -              reg_state[CTX_RCS_INDIRECT_CTX+1] = 0;
 -              reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8;
 -              reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0;
 +              ASSIGN_CTX_REG(reg_state, CTX_BB_PER_CTX_PTR, RING_BB_PER_CTX_PTR(ring->mmio_base), 0);
 +              ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX, RING_INDIRECT_CTX(ring->mmio_base), 0);
 +              ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX_OFFSET, RING_INDIRECT_CTX_OFFSET(ring->mmio_base), 0);
                if (ring->wa_ctx.obj) {
                        struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx;
                        uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj);
                                0x01;
                }
        }
 -      reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9);
 -      reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED;
 -      reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8;
 -      reg_state[CTX_CTX_TIMESTAMP+1] = 0;
 -      reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3);
 -      reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3);
 -      reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2);
 -      reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2);
 -      reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1);
 -      reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1);
 -      reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
 -      reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
 +      reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9) | MI_LRI_FORCE_POSTED;
 +      ASSIGN_CTX_REG(reg_state, CTX_CTX_TIMESTAMP, RING_CTX_TIMESTAMP(ring->mmio_base), 0);
 +      /* PDP values well be assigned later if needed */
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP3_UDW, GEN8_RING_PDP_UDW(ring, 3), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP3_LDW, GEN8_RING_PDP_LDW(ring, 3), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP2_UDW, GEN8_RING_PDP_UDW(ring, 2), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP2_LDW, GEN8_RING_PDP_LDW(ring, 2), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP1_UDW, GEN8_RING_PDP_UDW(ring, 1), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP1_LDW, GEN8_RING_PDP_LDW(ring, 1), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(ring, 0), 0);
 +      ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(ring, 0), 0);
  
        if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
                /* 64b PPGTT (48bit canonical)
  
        if (ring->id == RCS) {
                reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
 -              reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE;
 -              reg_state[CTX_R_PWR_CLK_STATE+1] = make_rpcs(dev);
 +              ASSIGN_CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE,
 +                             make_rpcs(dev));
        }
  
        kunmap_atomic(reg_state);
  #define _INTEL_LRC_H_
  
  #define GEN8_LR_CONTEXT_ALIGN 4096
+ #define GEN8_CSB_ENTRIES 6
+ #define GEN8_CSB_PTR_MASK 0x07
  
  /* Execlists regs */
 -#define RING_ELSP(ring)                       ((ring)->mmio_base+0x230)
 -#define RING_EXECLIST_STATUS_LO(ring) ((ring)->mmio_base+0x234)
 -#define RING_EXECLIST_STATUS_HI(ring) ((ring)->mmio_base+0x234 + 4)
 -#define RING_CONTEXT_CONTROL(ring)    ((ring)->mmio_base+0x244)
 +#define RING_ELSP(ring)                               _MMIO((ring)->mmio_base + 0x230)
 +#define RING_EXECLIST_STATUS_LO(ring)         _MMIO((ring)->mmio_base + 0x234)
 +#define RING_EXECLIST_STATUS_HI(ring)         _MMIO((ring)->mmio_base + 0x234 + 4)
 +#define RING_CONTEXT_CONTROL(ring)            _MMIO((ring)->mmio_base + 0x244)
  #define         CTX_CTRL_INHIBIT_SYN_CTX_SWITCH       (1 << 3)
  #define         CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT   (1 << 0)
  #define   CTX_CTRL_RS_CTX_ENABLE                (1 << 1)
 -#define RING_CONTEXT_STATUS_BUF_LO(ring, i)   ((ring)->mmio_base+0x370 + (i) * 8)
 -#define RING_CONTEXT_STATUS_BUF_HI(ring, i)   ((ring)->mmio_base+0x370 + (i) * 8 + 4)
 -#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0)
 +#define RING_CONTEXT_STATUS_BUF_LO(ring, i)   _MMIO((ring)->mmio_base + 0x370 + (i) * 8)
 +#define RING_CONTEXT_STATUS_BUF_HI(ring, i)   _MMIO((ring)->mmio_base + 0x370 + (i) * 8 + 4)
 +#define RING_CONTEXT_STATUS_PTR(ring)         _MMIO((ring)->mmio_base + 0x3a0)
  
  /* Logical Rings */
  int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request);
@@@ -68,11 -70,6 +70,11 @@@ static inline void intel_logical_ring_e
        iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
        ringbuf->tail += 4;
  }
 +static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf,
 +                                             i915_reg_t reg)
 +{
 +      intel_logical_ring_emit(ringbuf, i915_mmio_reg_offset(reg));
 +}
  
  /* Logical Ring Contexts */
  
@@@ -1135,7 -1135,7 +1135,7 @@@ static void vlv_compute_wm(struct intel
                case DRM_PLANE_TYPE_CURSOR:
                        for (level = 0; level < wm_state->num_levels; level++)
                                wm_state->sr[level].cursor =
-                                       wm_state->sr[level].cursor;
+                                       wm_state->wm[level].cursor;
                        break;
                case DRM_PLANE_TYPE_PRIMARY:
                        for (level = 0; level < wm_state->num_levels; level++)
@@@ -1708,6 -1708,13 +1708,6 @@@ static uint32_t ilk_wm_fbc(uint32_t pri
        return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
  }
  
 -struct skl_pipe_wm_parameters {
 -      bool active;
 -      uint32_t pipe_htotal;
 -      uint32_t pixel_rate; /* in KHz */
 -      struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
 -};
 -
  struct ilk_wm_maximums {
        uint16_t pri;
        uint16_t spr;
        uint16_t fbc;
  };
  
 -/* used in computing the new watermarks state */
 -struct intel_wm_config {
 -      unsigned int num_pipes_active;
 -      bool sprites_enabled;
 -      bool sprites_scaled;
 -};
 -
  /*
   * For both WM_PIPE and WM_LP.
   * mem_value must be in 0.1us units.
@@@ -1965,11 -1979,9 +1965,11 @@@ static void ilk_compute_wm_level(const 
                                 const struct intel_crtc *intel_crtc,
                                 int level,
                                 struct intel_crtc_state *cstate,
 +                               struct intel_plane_state *pristate,
 +                               struct intel_plane_state *sprstate,
 +                               struct intel_plane_state *curstate,
                                 struct intel_wm_level *result)
  {
 -      struct intel_plane *intel_plane;
        uint16_t pri_latency = dev_priv->wm.pri_latency[level];
        uint16_t spr_latency = dev_priv->wm.spr_latency[level];
        uint16_t cur_latency = dev_priv->wm.cur_latency[level];
                cur_latency *= 5;
        }
  
 -      for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) {
 -              struct intel_plane_state *pstate =
 -                      to_intel_plane_state(intel_plane->base.state);
 -
 -              switch (intel_plane->base.type) {
 -              case DRM_PLANE_TYPE_PRIMARY:
 -                      result->pri_val = ilk_compute_pri_wm(cstate, pstate,
 -                                                           pri_latency,
 -                                                           level);
 -                      result->fbc_val = ilk_compute_fbc_wm(cstate, pstate,
 -                                                           result->pri_val);
 -                      break;
 -              case DRM_PLANE_TYPE_OVERLAY:
 -                      result->spr_val = ilk_compute_spr_wm(cstate, pstate,
 -                                                           spr_latency);
 -                      break;
 -              case DRM_PLANE_TYPE_CURSOR:
 -                      result->cur_val = ilk_compute_cur_wm(cstate, pstate,
 -                                                           cur_latency);
 -                      break;
 -              }
 -      }
 -
 +      result->pri_val = ilk_compute_pri_wm(cstate, pristate,
 +                                           pri_latency, level);
 +      result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency);
 +      result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency);
 +      result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val);
        result->enable = true;
  }
  
@@@ -2244,19 -2274,34 +2244,19 @@@ static void skl_setup_wm_latency(struc
        intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
  }
  
 -static void ilk_compute_wm_config(struct drm_device *dev,
 -                                struct intel_wm_config *config)
 -{
 -      struct intel_crtc *intel_crtc;
 -
 -      /* Compute the currently _active_ config */
 -      for_each_intel_crtc(dev, intel_crtc) {
 -              const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
 -
 -              if (!wm->pipe_enabled)
 -                      continue;
 -
 -              config->sprites_enabled |= wm->sprites_enabled;
 -              config->sprites_scaled |= wm->sprites_scaled;
 -              config->num_pipes_active++;
 -      }
 -}
 -
  /* Compute new watermarks for the pipe */
 -static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
 -                                struct intel_pipe_wm *pipe_wm)
 +static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
 +                             struct drm_atomic_state *state)
  {
 -      struct drm_crtc *crtc = cstate->base.crtc;
 -      struct drm_device *dev = crtc->dev;
 +      struct intel_pipe_wm *pipe_wm;
 +      struct drm_device *dev = intel_crtc->base.dev;
        const struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      struct intel_crtc_state *cstate = NULL;
        struct intel_plane *intel_plane;
 +      struct drm_plane_state *ps;
 +      struct intel_plane_state *pristate = NULL;
        struct intel_plane_state *sprstate = NULL;
 +      struct intel_plane_state *curstate = NULL;
        int level, max_level = ilk_wm_max_level(dev);
        /* LP0 watermark maximums depend on this pipe alone */
        struct intel_wm_config config = {
        };
        struct ilk_wm_maximums max;
  
 +      cstate = intel_atomic_get_crtc_state(state, intel_crtc);
 +      if (IS_ERR(cstate))
 +              return PTR_ERR(cstate);
 +
 +      pipe_wm = &cstate->wm.optimal.ilk;
 +
        for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
 -              if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) {
 -                      sprstate = to_intel_plane_state(intel_plane->base.state);
 -                      break;
 -              }
 +              ps = drm_atomic_get_plane_state(state,
 +                                              &intel_plane->base);
 +              if (IS_ERR(ps))
 +                      return PTR_ERR(ps);
 +
 +              if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY)
 +                      pristate = to_intel_plane_state(ps);
 +              else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY)
 +                      sprstate = to_intel_plane_state(ps);
 +              else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
 +                      curstate = to_intel_plane_state(ps);
        }
  
        config.sprites_enabled = sprstate->visible;
                drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
  
        pipe_wm->pipe_enabled = cstate->base.active;
 -      pipe_wm->sprites_enabled = sprstate->visible;
 +      pipe_wm->sprites_enabled = config.sprites_enabled;
        pipe_wm->sprites_scaled = config.sprites_scaled;
  
        /* ILK/SNB: LP2+ watermarks only w/o sprites */
        if (config.sprites_scaled)
                max_level = 0;
  
 -      ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]);
 +      ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
 +                           pristate, sprstate, curstate, &pipe_wm->wm[0]);
  
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
 -              pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
 +              pipe_wm->linetime = hsw_compute_linetime_wm(dev,
 +                                                          &intel_crtc->base);
  
        /* LP0 watermarks always use 1/2 DDB partitioning */
        ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
  
        /* At least LP0 must be valid */
        if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
 -              return false;
 +              return -EINVAL;
  
        ilk_compute_wm_reg_maximums(dev, 1, &max);
  
        for (level = 1; level <= max_level; level++) {
                struct intel_wm_level wm = {};
  
 -              ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm);
 +              ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate,
 +                                   pristate, sprstate, curstate, &wm);
  
                /*
                 * Disable any watermark level that exceeds the
                pipe_wm->wm[level] = wm;
        }
  
 -      return true;
 +      return 0;
  }
  
  /*
@@@ -2349,9 -2378,7 +2349,9 @@@ static void ilk_merge_wm_level(struct d
        ret_wm->enable = true;
  
        for_each_intel_crtc(dev, intel_crtc) {
 -              const struct intel_pipe_wm *active = &intel_crtc->wm.active;
 +              const struct intel_crtc_state *cstate =
 +                      to_intel_crtc_state(intel_crtc->base.state);
 +              const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
                const struct intel_wm_level *wm = &active->wm[level];
  
                if (!active->pipe_enabled)
@@@ -2499,15 -2526,14 +2499,15 @@@ static void ilk_compute_wm_results(stru
  
        /* LP0 register values */
        for_each_intel_crtc(dev, intel_crtc) {
 +              const struct intel_crtc_state *cstate =
 +                      to_intel_crtc_state(intel_crtc->base.state);
                enum pipe pipe = intel_crtc->pipe;
 -              const struct intel_wm_level *r =
 -                      &intel_crtc->wm.active.wm[0];
 +              const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0];
  
                if (WARN_ON(!r->enable))
                        continue;
  
 -              results->wm_linetime[pipe] = intel_crtc->wm.active.linetime;
 +              results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime;
  
                results->wm_pipe[pipe] =
                        (r->pri_val << WM0_PIPE_PLANE_SHIFT) |
@@@ -2729,40 -2755,18 +2729,40 @@@ static bool ilk_disable_lp_wm(struct dr
  #define SKL_DDB_SIZE          896     /* in blocks */
  #define BXT_DDB_SIZE          512
  
 +/*
 + * Return the index of a plane in the SKL DDB and wm result arrays.  Primary
 + * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and
 + * other universal planes are in indices 1..n.  Note that this may leave unused
 + * indices between the top "sprite" plane and the cursor.
 + */
 +static int
 +skl_wm_plane_id(const struct intel_plane *plane)
 +{
 +      switch (plane->base.type) {
 +      case DRM_PLANE_TYPE_PRIMARY:
 +              return 0;
 +      case DRM_PLANE_TYPE_CURSOR:
 +              return PLANE_CURSOR;
 +      case DRM_PLANE_TYPE_OVERLAY:
 +              return plane->plane + 1;
 +      default:
 +              MISSING_CASE(plane->base.type);
 +              return plane->plane;
 +      }
 +}
 +
  static void
  skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
 -                                 struct drm_crtc *for_crtc,
 +                                 const struct intel_crtc_state *cstate,
                                   const struct intel_wm_config *config,
 -                                 const struct skl_pipe_wm_parameters *params,
                                   struct skl_ddb_entry *alloc /* out */)
  {
 +      struct drm_crtc *for_crtc = cstate->base.crtc;
        struct drm_crtc *crtc;
        unsigned int pipe_size, ddb_size;
        int nth_active_pipe;
  
 -      if (!params->active) {
 +      if (!cstate->base.active) {
                alloc->start = 0;
                alloc->end = 0;
                return;
@@@ -2814,7 -2818,12 +2814,12 @@@ void skl_ddb_get_hw_state(struct drm_i9
        int plane;
        u32 val;
  
+       memset(ddb, 0, sizeof(*ddb));
        for_each_pipe(dev_priv, pipe) {
+               if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe)))
+                       continue;
                for_each_plane(dev_priv, pipe, plane) {
                        val = I915_READ(PLANE_BUF_CFG(pipe, plane));
                        skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane],
  }
  
  static unsigned int
 -skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y)
 +skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
 +                           const struct drm_plane_state *pstate,
 +                           int y)
  {
 +      struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
 +      struct drm_framebuffer *fb = pstate->fb;
  
        /* for planar format */
 -      if (p->y_bytes_per_pixel) {
 +      if (fb->pixel_format == DRM_FORMAT_NV12) {
                if (y)  /* y-plane data rate */
 -                      return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel;
 +                      return intel_crtc->config->pipe_src_w *
 +                              intel_crtc->config->pipe_src_h *
 +                              drm_format_plane_cpp(fb->pixel_format, 0);
                else    /* uv-plane data rate */
 -                      return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel;
 +                      return (intel_crtc->config->pipe_src_w/2) *
 +                              (intel_crtc->config->pipe_src_h/2) *
 +                              drm_format_plane_cpp(fb->pixel_format, 1);
        }
  
        /* for packed formats */
 -      return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
 +      return intel_crtc->config->pipe_src_w *
 +              intel_crtc->config->pipe_src_h *
 +              drm_format_plane_cpp(fb->pixel_format, 0);
  }
  
  /*
   *   3 * 4096 * 8192  * 4 < 2^32
   */
  static unsigned int
 -skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
 -                               const struct skl_pipe_wm_parameters *params)
 +skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate)
  {
 +      struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
 +      struct drm_device *dev = intel_crtc->base.dev;
 +      const struct intel_plane *intel_plane;
        unsigned int total_data_rate = 0;
 -      int plane;
  
 -      for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
 -              const struct intel_plane_wm_parameters *p;
 +      for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
 +              const struct drm_plane_state *pstate = intel_plane->base.state;
  
 -              p = &params->plane[plane];
 -              if (!p->enabled)
 +              if (pstate->fb == NULL)
                        continue;
  
 -              total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */
 -              if (p->y_bytes_per_pixel) {
 -                      total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */
 -              }
 +              if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
 +                      continue;
 +
 +              /* packed/uv */
 +              total_data_rate += skl_plane_relative_data_rate(cstate,
 +                                                              pstate,
 +                                                              0);
 +
 +              if (pstate->fb->pixel_format == DRM_FORMAT_NV12)
 +                      /* y-plane */
 +                      total_data_rate += skl_plane_relative_data_rate(cstate,
 +                                                                      pstate,
 +                                                                      1);
        }
  
        return total_data_rate;
  }
  
  static void
 -skl_allocate_pipe_ddb(struct drm_crtc *crtc,
 -                    const struct intel_wm_config *config,
 -                    const struct skl_pipe_wm_parameters *params,
 +skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
                      struct skl_ddb_allocation *ddb /* out */)
  {
 +      struct drm_crtc *crtc = cstate->base.crtc;
        struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_i915_private *dev_priv = to_i915(dev);
 +      struct intel_wm_config *config = &dev_priv->wm.config;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      struct intel_plane *intel_plane;
        enum pipe pipe = intel_crtc->pipe;
        struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
        uint16_t alloc_size, start, cursor_blocks;
        uint16_t minimum[I915_MAX_PLANES];
        uint16_t y_minimum[I915_MAX_PLANES];
        unsigned int total_data_rate;
 -      int plane;
  
 -      skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc);
 +      skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc);
        alloc_size = skl_ddb_entry_size(alloc);
        if (alloc_size == 0) {
                memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
        alloc->end -= cursor_blocks;
  
        /* 1. Allocate the mininum required blocks for each active plane */
 -      for_each_plane(dev_priv, pipe, plane) {
 -              const struct intel_plane_wm_parameters *p;
 +      for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
 +              struct drm_plane *plane = &intel_plane->base;
 +              struct drm_framebuffer *fb = plane->state->fb;
 +              int id = skl_wm_plane_id(intel_plane);
  
 -              p = &params->plane[plane];
 -              if (!p->enabled)
 +              if (fb == NULL)
 +                      continue;
 +              if (plane->type == DRM_PLANE_TYPE_CURSOR)
                        continue;
  
 -              minimum[plane] = 8;
 -              alloc_size -= minimum[plane];
 -              y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0;
 -              alloc_size -= y_minimum[plane];
 +              minimum[id] = 8;
 +              alloc_size -= minimum[id];
 +              y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
 +              alloc_size -= y_minimum[id];
        }
  
        /*
         *
         * FIXME: we may not allocate every single block here.
         */
 -      total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
 +      total_data_rate = skl_get_total_relative_data_rate(cstate);
  
        start = alloc->start;
 -      for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
 -              const struct intel_plane_wm_parameters *p;
 +      for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
 +              struct drm_plane *plane = &intel_plane->base;
 +              struct drm_plane_state *pstate = intel_plane->base.state;
                unsigned int data_rate, y_data_rate;
                uint16_t plane_blocks, y_plane_blocks = 0;
 +              int id = skl_wm_plane_id(intel_plane);
  
 -              p = &params->plane[plane];
 -              if (!p->enabled)
 +              if (pstate->fb == NULL)
 +                      continue;
 +              if (plane->type == DRM_PLANE_TYPE_CURSOR)
                        continue;
  
 -              data_rate = skl_plane_relative_data_rate(p, 0);
 +              data_rate = skl_plane_relative_data_rate(cstate, pstate, 0);
  
                /*
                 * allocation for (packed formats) or (uv-plane part of planar format):
                 * promote the expression to 64 bits to avoid overflowing, the
                 * result is < available as data_rate / total_data_rate < 1
                 */
 -              plane_blocks = minimum[plane];
 +              plane_blocks = minimum[id];
                plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
                                        total_data_rate);
  
 -              ddb->plane[pipe][plane].start = start;
 -              ddb->plane[pipe][plane].end = start + plane_blocks;
 +              ddb->plane[pipe][id].start = start;
 +              ddb->plane[pipe][id].end = start + plane_blocks;
  
                start += plane_blocks;
  
                /*
                 * allocation for y_plane part of planar format:
                 */
 -              if (p->y_bytes_per_pixel) {
 -                      y_data_rate = skl_plane_relative_data_rate(p, 1);
 -                      y_plane_blocks = y_minimum[plane];
 +              if (pstate->fb->pixel_format == DRM_FORMAT_NV12) {
 +                      y_data_rate = skl_plane_relative_data_rate(cstate,
 +                                                                 pstate,
 +                                                                 1);
 +                      y_plane_blocks = y_minimum[id];
                        y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate,
                                                total_data_rate);
  
 -                      ddb->y_plane[pipe][plane].start = start;
 -                      ddb->y_plane[pipe][plane].end = start + y_plane_blocks;
 +                      ddb->y_plane[pipe][id].start = start;
 +                      ddb->y_plane[pipe][id].end = start + y_plane_blocks;
  
                        start += y_plane_blocks;
                }
@@@ -3059,27 -3041,104 +3064,27 @@@ static bool skl_ddb_allocation_changed(
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
 -      enum pipe pipe = intel_crtc->pipe;
 -
 -      if (memcmp(new_ddb->plane[pipe], cur_ddb->plane[pipe],
 -                 sizeof(new_ddb->plane[pipe])))
 -              return true;
  
 -      if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR],
 -                  sizeof(new_ddb->plane[pipe][PLANE_CURSOR])))
 +      /*
 +       * If ddb allocation of pipes changed, it may require recalculation of
 +       * watermarks
 +       */
 +      if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe)))
                return true;
  
        return false;
  }
  
 -static void skl_compute_wm_global_parameters(struct drm_device *dev,
 -                                           struct intel_wm_config *config)
 -{
 -      struct drm_crtc *crtc;
 -      struct drm_plane *plane;
 -
 -      list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
 -              config->num_pipes_active += to_intel_crtc(crtc)->active;
 -
 -      /* FIXME: I don't think we need those two global parameters on SKL */
 -      list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
 -              struct intel_plane *intel_plane = to_intel_plane(plane);
 -
 -              config->sprites_enabled |= intel_plane->wm.enabled;
 -              config->sprites_scaled |= intel_plane->wm.scaled;
 -      }
 -}
 -
 -static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
 -                                         struct skl_pipe_wm_parameters *p)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      enum pipe pipe = intel_crtc->pipe;
 -      struct drm_plane *plane;
 -      struct drm_framebuffer *fb;
 -      int i = 1; /* Index for sprite planes start */
 -
 -      p->active = intel_crtc->active;
 -      if (p->active) {
 -              p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
 -              p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
 -
 -              fb = crtc->primary->state->fb;
 -              /* For planar: Bpp is for uv plane, y_Bpp is for y plane */
 -              if (fb) {
 -                      p->plane[0].enabled = true;
 -                      p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
 -                              drm_format_plane_cpp(fb->pixel_format, 1) :
 -                              drm_format_plane_cpp(fb->pixel_format, 0);
 -                      p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
 -                              drm_format_plane_cpp(fb->pixel_format, 0) : 0;
 -                      p->plane[0].tiling = fb->modifier[0];
 -              } else {
 -                      p->plane[0].enabled = false;
 -                      p->plane[0].bytes_per_pixel = 0;
 -                      p->plane[0].y_bytes_per_pixel = 0;
 -                      p->plane[0].tiling = DRM_FORMAT_MOD_NONE;
 -              }
 -              p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
 -              p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
 -              p->plane[0].rotation = crtc->primary->state->rotation;
 -
 -              fb = crtc->cursor->state->fb;
 -              p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0;
 -              if (fb) {
 -                      p->plane[PLANE_CURSOR].enabled = true;
 -                      p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8;
 -                      p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w;
 -                      p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h;
 -              } else {
 -                      p->plane[PLANE_CURSOR].enabled = false;
 -                      p->plane[PLANE_CURSOR].bytes_per_pixel = 0;
 -                      p->plane[PLANE_CURSOR].horiz_pixels = 64;
 -                      p->plane[PLANE_CURSOR].vert_pixels = 64;
 -              }
 -      }
 -
 -      list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
 -              struct intel_plane *intel_plane = to_intel_plane(plane);
 -
 -              if (intel_plane->pipe == pipe &&
 -                      plane->type == DRM_PLANE_TYPE_OVERLAY)
 -                      p->plane[i++] = intel_plane->wm;
 -      }
 -}
 -
  static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 -                               struct skl_pipe_wm_parameters *p,
 -                               struct intel_plane_wm_parameters *p_params,
 +                               struct intel_crtc_state *cstate,
 +                               struct intel_plane *intel_plane,
                                 uint16_t ddb_allocation,
                                 int level,
                                 uint16_t *out_blocks, /* out */
                                 uint8_t *out_lines /* out */)
  {
 +      struct drm_plane *plane = &intel_plane->base;
 +      struct drm_framebuffer *fb = plane->state->fb;
        uint32_t latency = dev_priv->wm.skl_latency[level];
        uint32_t method1, method2;
        uint32_t plane_bytes_per_line, plane_blocks_per_line;
        uint32_t selected_result;
        uint8_t bytes_per_pixel;
  
 -      if (latency == 0 || !p->active || !p_params->enabled)
 +      if (latency == 0 || !cstate->base.active || !fb)
                return false;
  
 -      bytes_per_pixel = p_params->y_bytes_per_pixel ?
 -              p_params->y_bytes_per_pixel :
 -              p_params->bytes_per_pixel;
 -      method1 = skl_wm_method1(p->pixel_rate,
 +      bytes_per_pixel = drm_format_plane_cpp(fb->pixel_format, 0);
 +      method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
                                 bytes_per_pixel,
                                 latency);
 -      method2 = skl_wm_method2(p->pixel_rate,
 -                               p->pipe_htotal,
 -                               p_params->horiz_pixels,
 +      method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
 +                               cstate->base.adjusted_mode.crtc_htotal,
 +                               cstate->pipe_src_w,
                                 bytes_per_pixel,
 -                               p_params->tiling,
 +                               fb->modifier[0],
                                 latency);
  
 -      plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel;
 +      plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel;
        plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
  
 -      if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
 -          p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
 +      if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 +          fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
                uint32_t min_scanlines = 4;
                uint32_t y_tile_minimum;
 -              if (intel_rotation_90_or_270(p_params->rotation)) {
 -                      switch (p_params->bytes_per_pixel) {
 +              if (intel_rotation_90_or_270(plane->state->rotation)) {
 +                      int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
 +                              drm_format_plane_cpp(fb->pixel_format, 1) :
 +                              drm_format_plane_cpp(fb->pixel_format, 0);
 +
 +                      switch (bpp) {
                        case 1:
                                min_scanlines = 16;
                                break;
        res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
  
        if (level >= 1 && level <= 7) {
 -              if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
 -                  p_params->tiling == I915_FORMAT_MOD_Yf_TILED)
 +              if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 +                  fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)
                        res_lines += 4;
                else
                        res_blocks++;
  
  static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
                                 struct skl_ddb_allocation *ddb,
 -                               struct skl_pipe_wm_parameters *p,
 -                               enum pipe pipe,
 +                               struct intel_crtc_state *cstate,
                                 int level,
 -                               int num_planes,
                                 struct skl_wm_level *result)
  {
 +      struct drm_device *dev = dev_priv->dev;
 +      struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
 +      struct intel_plane *intel_plane;
        uint16_t ddb_blocks;
 -      int i;
 +      enum pipe pipe = intel_crtc->pipe;
 +
 +      for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
 +              int i = skl_wm_plane_id(intel_plane);
  
 -      for (i = 0; i < num_planes; i++) {
                ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]);
  
                result->plane_en[i] = skl_compute_plane_wm(dev_priv,
 -                                              p, &p->plane[i],
 +                                              cstate,
 +                                              intel_plane,
                                                ddb_blocks,
                                                level,
                                                &result->plane_res_b[i],
                                                &result->plane_res_l[i]);
        }
 -
 -      ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]);
 -      result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p,
 -                                               &p->plane[PLANE_CURSOR],
 -                                               ddb_blocks, level,
 -                                               &result->plane_res_b[PLANE_CURSOR],
 -                                               &result->plane_res_l[PLANE_CURSOR]);
  }
  
  static uint32_t
 -skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p)
 +skl_compute_linetime_wm(struct intel_crtc_state *cstate)
  {
 -      if (!to_intel_crtc(crtc)->active)
 +      if (!cstate->base.active)
                return 0;
  
 -      if (WARN_ON(p->pixel_rate == 0))
 +      if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0))
                return 0;
  
 -      return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
 +      return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000,
 +                          skl_pipe_pixel_rate(cstate));
  }
  
 -static void skl_compute_transition_wm(struct drm_crtc *crtc,
 -                                    struct skl_pipe_wm_parameters *params,
 +static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
                                      struct skl_wm_level *trans_wm /* out */)
  {
 +      struct drm_crtc *crtc = cstate->base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      int i;
 +      struct intel_plane *intel_plane;
  
 -      if (!params->active)
 +      if (!cstate->base.active)
                return;
  
        /* Until we know more, just disable transition WMs */
 -      for (i = 0; i < intel_num_planes(intel_crtc); i++)
 +      for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) {
 +              int i = skl_wm_plane_id(intel_plane);
 +
                trans_wm->plane_en[i] = false;
 -      trans_wm->plane_en[PLANE_CURSOR] = false;
 +      }
  }
  
 -static void skl_compute_pipe_wm(struct drm_crtc *crtc,
 +static void skl_compute_pipe_wm(struct intel_crtc_state *cstate,
                                struct skl_ddb_allocation *ddb,
 -                              struct skl_pipe_wm_parameters *params,
                                struct skl_pipe_wm *pipe_wm)
  {
 -      struct drm_device *dev = crtc->dev;
 +      struct drm_device *dev = cstate->base.crtc->dev;
        const struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int level, max_level = ilk_wm_max_level(dev);
  
        for (level = 0; level <= max_level; level++) {
 -              skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe,
 -                                   level, intel_num_planes(intel_crtc),
 -                                   &pipe_wm->wm[level]);
 +              skl_compute_wm_level(dev_priv, ddb, cstate,
 +                                   level, &pipe_wm->wm[level]);
        }
 -      pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
 +      pipe_wm->linetime = skl_compute_linetime_wm(cstate);
  
 -      skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm);
 +      skl_compute_transition_wm(cstate, &pipe_wm->trans_wm);
  }
  
  static void skl_compute_wm_results(struct drm_device *dev,
 -                                 struct skl_pipe_wm_parameters *p,
                                   struct skl_pipe_wm *p_wm,
                                   struct skl_wm_values *r,
                                   struct intel_crtc *intel_crtc)
        r->wm_linetime[pipe] = p_wm->linetime;
  }
  
 -static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg,
 +static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
 +                              i915_reg_t reg,
                                const struct skl_ddb_entry *entry)
  {
        if (entry->end)
@@@ -3473,25 -3533,28 +3478,25 @@@ static void skl_flush_wm_values(struct 
  }
  
  static bool skl_update_pipe_wm(struct drm_crtc *crtc,
 -                             struct skl_pipe_wm_parameters *params,
 -                             struct intel_wm_config *config,
                               struct skl_ddb_allocation *ddb, /* out */
                               struct skl_pipe_wm *pipe_wm /* out */)
  {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
  
 -      skl_compute_wm_pipe_parameters(crtc, params);
 -      skl_allocate_pipe_ddb(crtc, config, params, ddb);
 -      skl_compute_pipe_wm(crtc, ddb, params, pipe_wm);
 +      skl_allocate_pipe_ddb(cstate, ddb);
 +      skl_compute_pipe_wm(cstate, ddb, pipe_wm);
  
 -      if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm)))
 +      if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm)))
                return false;
  
 -      intel_crtc->wm.skl_active = *pipe_wm;
 +      intel_crtc->wm.active.skl = *pipe_wm;
  
        return true;
  }
  
  static void skl_update_other_pipe_wm(struct drm_device *dev,
                                     struct drm_crtc *crtc,
 -                                   struct intel_wm_config *config,
                                     struct skl_wm_values *r)
  {
        struct intel_crtc *intel_crtc;
         */
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
                                base.head) {
 -              struct skl_pipe_wm_parameters params = {};
                struct skl_pipe_wm pipe_wm = {};
                bool wm_changed;
  
                        continue;
  
                wm_changed = skl_update_pipe_wm(&intel_crtc->base,
 -                                              &params, config,
                                                &r->ddb, &pipe_wm);
  
                /*
                 */
                WARN_ON(!wm_changed);
  
 -              skl_compute_wm_results(dev, &params, &pipe_wm, r, intel_crtc);
 +              skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
                r->dirty[intel_crtc->pipe] = true;
        }
  }
@@@ -3561,9 -3626,10 +3566,9 @@@ static void skl_update_wm(struct drm_cr
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct skl_pipe_wm_parameters params = {};
        struct skl_wm_values *results = &dev_priv->wm.skl_results;
 -      struct skl_pipe_wm pipe_wm = {};
 -      struct intel_wm_config config = {};
 +      struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 +      struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl;
  
  
        /* Clear all dirty flags */
  
        skl_clear_wm(results, intel_crtc->pipe);
  
 -      skl_compute_wm_global_parameters(dev, &config);
 -
 -      if (!skl_update_pipe_wm(crtc, &params, &config,
 -                              &results->ddb, &pipe_wm))
 +      if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
                return;
  
 -      skl_compute_wm_results(dev, &params, &pipe_wm, results, intel_crtc);
 +      skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
        results->dirty[intel_crtc->pipe] = true;
  
 -      skl_update_other_pipe_wm(dev, crtc, &config, results);
 +      skl_update_other_pipe_wm(dev, crtc, results);
        skl_write_wm_values(dev_priv, results);
        skl_flush_wm_values(dev_priv, results);
  
        dev_priv->wm.skl_hw = *results;
  }
  
 -static void
 -skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
 -                   uint32_t sprite_width, uint32_t sprite_height,
 -                   int pixel_size, bool enabled, bool scaled)
 +static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
  {
 -      struct intel_plane *intel_plane = to_intel_plane(plane);
 -      struct drm_framebuffer *fb = plane->state->fb;
 -
 -      intel_plane->wm.enabled = enabled;
 -      intel_plane->wm.scaled = scaled;
 -      intel_plane->wm.horiz_pixels = sprite_width;
 -      intel_plane->wm.vert_pixels = sprite_height;
 -      intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE;
 -
 -      /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */
 -      intel_plane->wm.bytes_per_pixel =
 -              (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
 -              drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size;
 -      intel_plane->wm.y_bytes_per_pixel =
 -              (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
 -              drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0;
 -
 -      /*
 -       * Framebuffer can be NULL on plane disable, but it does not
 -       * matter for watermarks if we assume no tiling in that case.
 -       */
 -      if (fb)
 -              intel_plane->wm.tiling = fb->modifier[0];
 -      intel_plane->wm.rotation = plane->state->rotation;
 -
 -      skl_update_wm(crtc);
 -}
 -
 -static void ilk_update_wm(struct drm_crtc *crtc)
 -{
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_device *dev = dev_priv->dev;
 +      struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
        struct ilk_wm_maximums max;
 +      struct intel_wm_config *config = &dev_priv->wm.config;
        struct ilk_wm_values results = {};
        enum intel_ddb_partitioning partitioning;
 -      struct intel_pipe_wm pipe_wm = {};
 -      struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
 -      struct intel_wm_config config = {};
 -
 -      WARN_ON(cstate->base.active != intel_crtc->active);
  
 -      intel_compute_pipe_wm(cstate, &pipe_wm);
 -
 -      if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
 -              return;
 -
 -      intel_crtc->wm.active = pipe_wm;
 -
 -      ilk_compute_wm_config(dev, &config);
 -
 -      ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max);
 -      ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
 +      ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max);
 +      ilk_wm_merge(dev, config, &max, &lp_wm_1_2);
  
        /* 5/6 split only in single pipe config on IVB+ */
        if (INTEL_INFO(dev)->gen >= 7 &&
 -          config.num_pipes_active == 1 && config.sprites_enabled) {
 -              ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
 -              ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
 +          config->num_pipes_active == 1 && config->sprites_enabled) {
 +              ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max);
 +              ilk_wm_merge(dev, config, &max, &lp_wm_5_6);
  
                best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
        } else {
        ilk_write_wm_values(dev_priv, &results);
  }
  
 -static void
 -ilk_update_sprite_wm(struct drm_plane *plane,
 -                   struct drm_crtc *crtc,
 -                   uint32_t sprite_width, uint32_t sprite_height,
 -                   int pixel_size, bool enabled, bool scaled)
 +static void ilk_update_wm(struct drm_crtc *crtc)
  {
 -      struct drm_device *dev = plane->dev;
 -      struct intel_plane *intel_plane = to_intel_plane(plane);
 +      struct drm_i915_private *dev_priv = to_i915(crtc->dev);
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 +
 +      WARN_ON(cstate->base.active != intel_crtc->active);
  
        /*
         * IVB workaround: must disable low power watermarks for at least
         *
         * WaCxSRDisabledForSpriteScaling:ivb
         */
 -      if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
 -              intel_wait_for_vblank(dev, intel_plane->pipe);
 +      if (cstate->disable_lp_wm) {
 +              ilk_disable_lp_wm(crtc->dev);
 +              intel_wait_for_vblank(crtc->dev, intel_crtc->pipe);
 +      }
  
 -      ilk_update_wm(crtc);
 +      intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
 +
 +      ilk_program_watermarks(dev_priv);
  }
  
  static void skl_pipe_wm_active_state(uint32_t val,
@@@ -3691,8 -3805,7 +3696,8 @@@ static void skl_pipe_wm_get_hw_state(st
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct skl_wm_values *hw = &dev_priv->wm.skl_hw;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      struct skl_pipe_wm *active = &intel_crtc->wm.skl_active;
 +      struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 +      struct skl_pipe_wm *active = &cstate->wm.optimal.skl;
        enum pipe pipe = intel_crtc->pipe;
        int level, i, max_level;
        uint32_t temp;
  
        temp = hw->plane_trans[pipe][PLANE_CURSOR];
        skl_pipe_wm_active_state(temp, active, true, true, i, 0);
 +
 +      intel_crtc->wm.active.skl = *active;
  }
  
  void skl_wm_get_hw_state(struct drm_device *dev)
@@@ -3757,10 -3868,9 +3762,10 @@@ static void ilk_pipe_wm_get_hw_state(st
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct ilk_wm_values *hw = &dev_priv->wm.hw;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      struct intel_pipe_wm *active = &intel_crtc->wm.active;
 +      struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 +      struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
        enum pipe pipe = intel_crtc->pipe;
 -      static const unsigned int wm0_pipe_reg[] = {
 +      static const i915_reg_t wm0_pipe_reg[] = {
                [PIPE_A] = WM0_PIPEA_ILK,
                [PIPE_B] = WM0_PIPEB_ILK,
                [PIPE_C] = WM0_PIPEC_IVB,
                for (level = 0; level <= max_level; level++)
                        active->wm[level].enable = true;
        }
 +
 +      intel_crtc->wm.active.ilk = *active;
  }
  
  #define _FW_WM(value, plane) \
@@@ -4024,6 -4132,21 +4029,6 @@@ void intel_update_watermarks(struct drm
                dev_priv->display.update_wm(crtc);
  }
  
 -void intel_update_sprite_watermarks(struct drm_plane *plane,
 -                                  struct drm_crtc *crtc,
 -                                  uint32_t sprite_width,
 -                                  uint32_t sprite_height,
 -                                  int pixel_size,
 -                                  bool enabled, bool scaled)
 -{
 -      struct drm_i915_private *dev_priv = plane->dev->dev_private;
 -
 -      if (dev_priv->display.update_sprite_wm)
 -              dev_priv->display.update_sprite_wm(plane, crtc,
 -                                                 sprite_width, sprite_height,
 -                                                 pixel_size, enabled, scaled);
 -}
 -
  /**
   * Lock protecting IPS related data structures
   */
@@@ -4291,7 -4414,7 +4296,7 @@@ static void gen6_set_rps(struct drm_dev
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
 -      if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0))
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                return;
  
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
        POSTING_READ(GEN6_RPNSWREQ);
  
        dev_priv->rps.cur_freq = val;
-       trace_intel_gpu_freq_change(val * 50);
+       trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
  }
  
  static void valleyview_set_rps(struct drm_device *dev, u8 val)
@@@ -4566,8 -4689,7 +4571,8 @@@ static void gen6_init_rps_frequencies(s
        dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
  
        dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
 -      if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) {
 +      if (IS_HASWELL(dev) || IS_BROADWELL(dev) ||
 +          IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                ret = sandybridge_pcode_read(dev_priv,
                                        HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
                                        &ddcc_status);
                                        dev_priv->rps.max_freq);
        }
  
 -      if (IS_SKYLAKE(dev)) {
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                /* Store the frequency values in 16.66 MHZ units, which is
                   the natural hardware unit for SKL */
                dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
@@@ -4616,7 -4738,7 +4621,7 @@@ static void gen9_enable_rps(struct drm_
        gen6_init_rps_frequencies(dev);
  
        /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
 -      if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
                return;
        }
@@@ -4661,7 -4783,7 +4666,7 @@@ static void gen9_enable_rc6(struct drm_
  
        /* WaRsDoubleRc6WrlWithCoarsePowerGating: Doubling WRL only when CPG is enabled */
        if (IS_SKYLAKE(dev) && !((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) &&
 -                               (INTEL_REVID(dev) <= SKL_REVID_E0)))
 +                               IS_SKL_REVID(dev, 0, SKL_REVID_E0)))
                I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16);
        else
                I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16);
        DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
                        "on" : "off");
        /* WaRsUseTimeoutMode */
 -      if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) {
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */
                I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
                           GEN7_RC_CTL_TO_MODE |
         * 3b: Enable Coarse Power Gating only when RC6 is enabled.
         * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
         */
 -      if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
 -          ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1) ||
 +          ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) &&
 +           IS_SKL_REVID(dev, 0, SKL_REVID_E0)))
                I915_WRITE(GEN9_PG_ENABLE, 0);
        else
                I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
@@@ -4935,7 -5056,7 +4940,7 @@@ static void __gen6_update_ring_freq(str
        /* convert DDR frequency from units of 266.6MHz to bandwidth */
        min_ring_freq = mult_frac(min_ring_freq, 8, 3);
  
 -      if (IS_SKYLAKE(dev)) {
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                /* Convert GT frequency to 50 HZ units */
                min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER;
                max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER;
                int diff = max_gpu_freq - gpu_freq;
                unsigned int ia_freq = 0, ring_freq = 0;
  
 -              if (IS_SKYLAKE(dev)) {
 +              if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                        /*
                         * ring_freq = 2 * GT. ring_freq is in 100MHz units
                         * No floor required for ring frequency on SKL.
@@@ -6081,7 -6202,7 +6086,7 @@@ static void intel_gen6_powersave_work(s
        } else if (INTEL_INFO(dev)->gen >= 9) {
                gen9_enable_rc6(dev);
                gen9_enable_rps(dev);
 -              if (IS_SKYLAKE(dev))
 +              if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                        __gen6_update_ring_freq(dev);
        } else if (IS_BROADWELL(dev)) {
                gen8_enable_rps(dev);
@@@ -6937,6 -7058,7 +6942,6 @@@ void intel_init_pm(struct drm_device *d
                        dev_priv->display.init_clock_gating =
                                bxt_init_clock_gating;
                dev_priv->display.update_wm = skl_update_wm;
 -              dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
        } else if (HAS_PCH_SPLIT(dev)) {
                ilk_setup_wm_latency(dev);
  
                    (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
                     dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
                        dev_priv->display.update_wm = ilk_update_wm;
 -                      dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
 +                      dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
                } else {
                        DRM_DEBUG_KMS("Failed to read display plane latency. "
                                      "Disable CxSR\n");
@@@ -7133,7 -7255,8 +7138,8 @@@ static int chv_freq_opcode(struct drm_i
  int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
  {
        if (IS_GEN9(dev_priv->dev))
-               return (val * GT_FREQUENCY_MULTIPLIER) / GEN9_FREQ_SCALER;
+               return DIV_ROUND_CLOSEST(val * GT_FREQUENCY_MULTIPLIER,
+                                        GEN9_FREQ_SCALER);
        else if (IS_CHERRYVIEW(dev_priv->dev))
                return chv_gpu_freq(dev_priv, val);
        else if (IS_VALLEYVIEW(dev_priv->dev))
  int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
  {
        if (IS_GEN9(dev_priv->dev))
-               return (val * GEN9_FREQ_SCALER) / GT_FREQUENCY_MULTIPLIER;
+               return DIV_ROUND_CLOSEST(val * GEN9_FREQ_SCALER,
+                                        GT_FREQUENCY_MULTIPLIER);
        else if (IS_CHERRYVIEW(dev_priv->dev))
                return chv_freq_opcode(dev_priv, val);
        else if (IS_VALLEYVIEW(dev_priv->dev))
                return byt_freq_opcode(dev_priv, val);
        else
-               return val / GT_FREQUENCY_MULTIPLIER;
+               return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
  }
  
  struct request_boost {
@@@ -347,6 -347,7 +347,7 @@@ gen7_render_ring_flush(struct drm_i915_
        if (flush_domains) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
        if (invalidate_domains) {
                flags |= PIPE_CONTROL_TLB_INVALIDATE;
@@@ -418,6 -419,7 +419,7 @@@ gen8_render_ring_flush(struct drm_i915_
        if (flush_domains) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
        if (invalidate_domains) {
                flags |= PIPE_CONTROL_TLB_INVALIDATE;
@@@ -479,7 -481,7 +481,7 @@@ static void intel_ring_setup_status_pag
  {
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
 -      u32 mmio = 0;
 +      i915_reg_t mmio;
  
        /* The ring status page addresses are no longer next to the rest of
         * the ring registers as of gen7.
         * invalidating the TLB?
         */
        if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
 -              u32 reg = RING_INSTPM(ring->mmio_base);
 +              i915_reg_t reg = RING_INSTPM(ring->mmio_base);
  
                /* ring should be idle before issuing a sync flush*/
                WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
@@@ -731,7 -733,7 +733,7 @@@ static int intel_ring_workarounds_emit(
  
        intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
        for (i = 0; i < w->count; i++) {
 -              intel_ring_emit(ring, w->reg[i].addr);
 +              intel_ring_emit_reg(ring, w->reg[i].addr);
                intel_ring_emit(ring, w->reg[i].value);
        }
        intel_ring_emit(ring, MI_NOOP);
@@@ -764,8 -766,7 +766,8 @@@ static int intel_rcs_ctx_init(struct dr
  }
  
  static int wa_add(struct drm_i915_private *dev_priv,
 -                const u32 addr, const u32 mask, const u32 val)
 +                i915_reg_t addr,
 +                const u32 mask, const u32 val)
  {
        const u32 idx = dev_priv->workarounds.count;
  
@@@ -923,15 -924,17 +925,15 @@@ static int gen9_init_workarounds(struc
        WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
                          GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
  
 -      if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) == SKL_REVID_A0 ||
 -          INTEL_REVID(dev) == SKL_REVID_B0)) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) {
 -              /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
 +      /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
                                  GEN9_DG_MIRROR_FIX_ENABLE);
 -      }
  
 -      if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) {
 -              /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
 +      /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
                                  GEN9_RHWO_OPTIMIZATION_DISABLE);
                /*
                 */
        }
  
 -      if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) ||
 -          IS_BROXTON(dev)) {
 -              /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
 +      /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
 +      if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER) || IS_BROXTON(dev))
                WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
                                  GEN9_ENABLE_YV12_BUGFIX);
 -      }
  
        /* Wa4x4STCOptimizationDisable:skl,bxt */
        /* WaDisablePartialResolveInVc:skl,bxt */
                          GEN9_CCS_TLB_PREFETCH_ENABLE);
  
        /* WaDisableMaskBasedCammingInRCC:skl,bxt */
 -      if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_C0) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0))
 +      if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_C0) ||
 +          IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
                                  PIXEL_MASK_CAMMING_DISABLE);
  
        /* WaForceContextSaveRestoreNonCoherent:skl,bxt */
        tmp = HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT;
 -      if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_F0) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) >= BXT_REVID_B0))
 +      if (IS_SKL_REVID(dev, SKL_REVID_F0, SKL_REVID_F0) ||
 +          IS_BXT_REVID(dev, BXT_REVID_B0, REVID_FOREVER))
                tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE;
        WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp);
  
        /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */
 -      if (IS_SKYLAKE(dev) ||
 -          (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_B0)) {
 +      if (IS_SKYLAKE(dev) || IS_BXT_REVID(dev, 0, BXT_REVID_B0))
                WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
                                  GEN8_SAMPLER_POWER_BYPASS_DIS);
 -      }
  
        /* WaDisableSTUnitPowerOptimization:skl,bxt */
        WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
@@@ -1031,7 -1038,7 +1033,7 @@@ static int skl_init_workarounds(struct 
        if (ret)
                return ret;
  
 -      if (INTEL_REVID(dev) <= SKL_REVID_D0) {
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
                /* WaDisableHDCInvalidation:skl */
                I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
                           BDW_DISABLE_HDC_INVALIDATION);
        /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
         * involving this register should also be added to WA batch as required.
         */
 -      if (INTEL_REVID(dev) <= SKL_REVID_E0)
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_E0))
                /* WaDisableLSQCROPERFforOCL:skl */
                I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
                           GEN8_LQSC_RO_PERF_DIS);
  
        /* WaEnableGapsTsvCreditFix:skl */
 -      if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) {
 +      if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER)) {
                I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
                                           GEN9_GAPS_TSV_CREDIT_DISABLE));
        }
  
        /* WaDisablePowerCompilerClockGating:skl */
 -      if (INTEL_REVID(dev) == SKL_REVID_B0)
 +      if (IS_SKL_REVID(dev, SKL_REVID_B0, SKL_REVID_B0))
                WA_SET_BIT_MASKED(HIZ_CHICKEN,
                                  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
  
 -      if (INTEL_REVID(dev) <= SKL_REVID_D0) {
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
                /*
                 *Use Force Non-Coherent whenever executing a 3D context. This
                 * is a workaround for a possible hang in the unlikely event
                                  HDC_FORCE_NON_COHERENT);
        }
  
 -      if (INTEL_REVID(dev) == SKL_REVID_C0 ||
 -          INTEL_REVID(dev) == SKL_REVID_D0)
 -              /* WaBarrierPerformanceFixDisable:skl */
 +      /* WaBarrierPerformanceFixDisable:skl */
 +      if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0))
                WA_SET_BIT_MASKED(HDC_CHICKEN0,
                                  HDC_FENCE_DEST_SLM_DISABLE |
                                  HDC_BARRIER_PERFORMANCE_DISABLE);
  
        /* WaDisableSbeCacheDispatchPortSharing:skl */
 -      if (INTEL_REVID(dev) <= SKL_REVID_F0) {
 +      if (IS_SKL_REVID(dev, 0, SKL_REVID_F0))
                WA_SET_BIT_MASKED(
                        GEN7_HALF_SLICE_CHICKEN1,
                        GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
 -      }
  
        return skl_tune_iz_hashing(ring);
  }
@@@ -1098,11 -1107,11 +1100,11 @@@ static int bxt_init_workarounds(struct 
  
        /* WaStoreMultiplePTEenable:bxt */
        /* This is a requirement according to Hardware specification */
 -      if (INTEL_REVID(dev) == BXT_REVID_A0)
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
  
        /* WaSetClckGatingDisableMedia:bxt */
 -      if (INTEL_REVID(dev) == BXT_REVID_A0) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
                                            ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
        }
                          STALL_DOP_GATING_DISABLE);
  
        /* WaDisableSbeCacheDispatchPortSharing:bxt */
 -      if (INTEL_REVID(dev) <= BXT_REVID_B0) {
 +      if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) {
                WA_SET_BIT_MASKED(
                        GEN7_HALF_SLICE_CHICKEN1,
                        GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
@@@ -1310,13 -1319,11 +1312,13 @@@ static int gen6_signal(struct drm_i915_
                return ret;
  
        for_each_ring(useless, dev_priv, i) {
 -              u32 mbox_reg = signaller->semaphore.mbox.signal[i];
 -              if (mbox_reg != GEN6_NOSYNC) {
 +              i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[i];
 +
 +              if (i915_mmio_reg_valid(mbox_reg)) {
                        u32 seqno = i915_gem_request_get_seqno(signaller_req);
 +
                        intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
 -                      intel_ring_emit(signaller, mbox_reg);
 +                      intel_ring_emit_reg(signaller, mbox_reg);
                        intel_ring_emit(signaller, seqno);
                }
        }
@@@ -1997,35 -2004,11 +1999,35 @@@ static int init_phys_status_page(struc
  
  void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
  {
 -      iounmap(ringbuf->virtual_start);
 +      if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
 +              vunmap(ringbuf->virtual_start);
 +      else
 +              iounmap(ringbuf->virtual_start);
        ringbuf->virtual_start = NULL;
        i915_gem_object_ggtt_unpin(ringbuf->obj);
  }
  
 +static u32 *vmap_obj(struct drm_i915_gem_object *obj)
 +{
 +      struct sg_page_iter sg_iter;
 +      struct page **pages;
 +      void *addr;
 +      int i;
 +
 +      pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
 +      if (pages == NULL)
 +              return NULL;
 +
 +      i = 0;
 +      for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0)
 +              pages[i++] = sg_page_iter_page(&sg_iter);
 +
 +      addr = vmap(pages, i, 0, PAGE_KERNEL);
 +      drm_free_large(pages);
 +
 +      return addr;
 +}
 +
  int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
                                     struct intel_ringbuffer *ringbuf)
  {
        struct drm_i915_gem_object *obj = ringbuf->obj;
        int ret;
  
 -      ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
 -      if (ret)
 -              return ret;
 +      if (HAS_LLC(dev_priv) && !obj->stolen) {
 +              ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, 0);
 +              if (ret)
 +                      return ret;
  
 -      ret = i915_gem_object_set_to_gtt_domain(obj, true);
 -      if (ret) {
 -              i915_gem_object_ggtt_unpin(obj);
 -              return ret;
 -      }
 +              ret = i915_gem_object_set_to_cpu_domain(obj, true);
 +              if (ret) {
 +                      i915_gem_object_ggtt_unpin(obj);
 +                      return ret;
 +              }
 +
 +              ringbuf->virtual_start = vmap_obj(obj);
 +              if (ringbuf->virtual_start == NULL) {
 +                      i915_gem_object_ggtt_unpin(obj);
 +                      return -ENOMEM;
 +              }
 +      } else {
 +              ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
 +              if (ret)
 +                      return ret;
  
 -      ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
 -                      i915_gem_obj_ggtt_offset(obj), ringbuf->size);
 -      if (ringbuf->virtual_start == NULL) {
 -              i915_gem_object_ggtt_unpin(obj);
 -              return -EINVAL;
 +              ret = i915_gem_object_set_to_gtt_domain(obj, true);
 +              if (ret) {
 +                      i915_gem_object_ggtt_unpin(obj);
 +                      return ret;
 +              }
 +
 +              ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
 +                                                  i915_gem_obj_ggtt_offset(obj), ringbuf->size);
 +              if (ringbuf->virtual_start == NULL) {
 +                      i915_gem_object_ggtt_unpin(obj);
 +                      return -EINVAL;
 +              }
        }
  
        return 0;
@@@ -2105,14 -2070,10 +2107,14 @@@ intel_engine_create_ringbuffer(struct i
        int ret;
  
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 -      if (ring == NULL)
 +      if (ring == NULL) {
 +              DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
 +                               engine->name);
                return ERR_PTR(-ENOMEM);
 +      }
  
        ring->ring = engine;
 +      list_add(&ring->link, &engine->buffers);
  
        ring->size = size;
        /* Workaround an erratum on the i830 which causes a hang if
  
        ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
        if (ret) {
 -              DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
 -                        engine->name, ret);
 +              DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
 +                               engine->name, ret);
 +              list_del(&ring->link);
                kfree(ring);
                return ERR_PTR(ret);
        }
@@@ -2142,7 -2102,6 +2144,7 @@@ voi
  intel_ringbuffer_free(struct intel_ringbuffer *ring)
  {
        intel_destroy_ringbuffer_obj(ring);
 +      list_del(&ring->link);
        kfree(ring);
  }
  
@@@ -2158,7 -2117,6 +2160,7 @@@ static int intel_init_ring_buffer(struc
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
        INIT_LIST_HEAD(&ring->execlist_queue);
 +      INIT_LIST_HEAD(&ring->buffers);
        i915_gem_batch_pool_init(dev, &ring->batch_pool);
        memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
  
@@@ -49,6 -49,9 +49,6 @@@
   * present for a given platform.
   */
  
 -#define GEN9_ENABLE_DC5(dev) 0
 -#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev)
 -
  #define for_each_power_well(i, power_well, domain_mask, power_domains)        \
        for (i = 0;                                                     \
             i < (power_domains)->power_well_count &&                   \
@@@ -241,6 -244,12 +241,6 @@@ static void skl_power_well_post_enable(
                gen8_irq_power_well_post_enable(dev_priv,
                                                1 << PIPE_C | 1 << PIPE_B);
        }
 -
 -      if (power_well->data == SKL_DISP_PW_1) {
 -              if (!dev_priv->power_domains.initializing)
 -                      intel_prepare_ddi(dev);
 -              gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_A);
 -      }
  }
  
  static void hsw_set_power_well(struct drm_i915_private *dev_priv,
        BIT(POWER_DOMAIN_TRANSCODER_C) |                \
        BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) |         \
        BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) |         \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_E_LANES) |            \
        BIT(POWER_DOMAIN_AUX_B) |                       \
        BIT(POWER_DOMAIN_AUX_C) |                       \
        BIT(POWER_DOMAIN_AUX_D) |                       \
        BIT(POWER_DOMAIN_AUDIO) |                       \
        BIT(POWER_DOMAIN_VGA) |                         \
        BIT(POWER_DOMAIN_INIT))
 -#define SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS (               \
 -      SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
 -      BIT(POWER_DOMAIN_PLLS) |                        \
 -      BIT(POWER_DOMAIN_PIPE_A) |                      \
 -      BIT(POWER_DOMAIN_TRANSCODER_EDP) |              \
 -      BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) |         \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
 -      BIT(POWER_DOMAIN_AUX_A) |                       \
 -      BIT(POWER_DOMAIN_INIT))
  #define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS (           \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_A_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_E_LANES) |            \
        BIT(POWER_DOMAIN_INIT))
  #define SKL_DISPLAY_DDI_B_POWER_DOMAINS (             \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |            \
        BIT(POWER_DOMAIN_INIT))
  #define SKL_DISPLAY_DDI_C_POWER_DOMAINS (             \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |            \
        BIT(POWER_DOMAIN_INIT))
  #define SKL_DISPLAY_DDI_D_POWER_DOMAINS (             \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |            \
        BIT(POWER_DOMAIN_INIT))
 -#define SKL_DISPLAY_MISC_IO_POWER_DOMAINS (           \
 -      SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |         \
 -      BIT(POWER_DOMAIN_PLLS) |                        \
 +#define SKL_DISPLAY_DC_OFF_POWER_DOMAINS (            \
 +      SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
 +      BIT(POWER_DOMAIN_MODESET) |                     \
 +      BIT(POWER_DOMAIN_AUX_A) |                       \
        BIT(POWER_DOMAIN_INIT))
  #define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS (         \
 -      (POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS |  \
 +      (POWER_DOMAIN_MASK & ~(                         \
        SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
 -      SKL_DISPLAY_DDI_A_E_POWER_DOMAINS |             \
 -      SKL_DISPLAY_DDI_B_POWER_DOMAINS |               \
 -      SKL_DISPLAY_DDI_C_POWER_DOMAINS |               \
 -      SKL_DISPLAY_DDI_D_POWER_DOMAINS |               \
 -      SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) |           \
 +      SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) |            \
        BIT(POWER_DOMAIN_INIT))
  
  #define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS (               \
        BIT(POWER_DOMAIN_TRANSCODER_C) |                \
        BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) |         \
        BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) |         \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |            \
        BIT(POWER_DOMAIN_AUX_B) |                       \
        BIT(POWER_DOMAIN_AUX_C) |                       \
        BIT(POWER_DOMAIN_AUDIO) |                       \
        BIT(POWER_DOMAIN_VGA) |                         \
 +      BIT(POWER_DOMAIN_GMBUS) |                       \
        BIT(POWER_DOMAIN_INIT))
  #define BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS (               \
        BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
        BIT(POWER_DOMAIN_PIPE_A) |                      \
        BIT(POWER_DOMAIN_TRANSCODER_EDP) |              \
        BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) |         \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_A_LANES) |            \
        BIT(POWER_DOMAIN_AUX_A) |                       \
        BIT(POWER_DOMAIN_PLLS) |                        \
        BIT(POWER_DOMAIN_INIT))
 +#define BXT_DISPLAY_DC_OFF_POWER_DOMAINS (            \
 +      BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
 +      BIT(POWER_DOMAIN_MODESET) |                     \
 +      BIT(POWER_DOMAIN_AUX_A) |                       \
 +      BIT(POWER_DOMAIN_INIT))
  #define BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS (         \
        (POWER_DOMAIN_MASK & ~(BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS |  \
        BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) |       \
@@@ -390,74 -416,46 +390,74 @@@ static void assert_can_disable_dc9(stru
          */
  }
  
 -void bxt_enable_dc9(struct drm_i915_private *dev_priv)
 +static void gen9_set_dc_state_debugmask_memory_up(
 +                      struct drm_i915_private *dev_priv)
  {
        uint32_t val;
  
 -      assert_can_enable_dc9(dev_priv);
 +      /* The below bit doesn't need to be cleared ever afterwards */
 +      val = I915_READ(DC_STATE_DEBUG);
 +      if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) {
 +              val |= DC_STATE_DEBUG_MASK_MEMORY_UP;
 +              I915_WRITE(DC_STATE_DEBUG, val);
 +              POSTING_READ(DC_STATE_DEBUG);
 +      }
 +}
  
 -      DRM_DEBUG_KMS("Enabling DC9\n");
 +static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
 +{
 +      uint32_t val;
 +      uint32_t mask;
 +
 +      mask = DC_STATE_EN_UPTO_DC5;
 +      if (IS_BROXTON(dev_priv))
 +              mask |= DC_STATE_EN_DC9;
 +      else
 +              mask |= DC_STATE_EN_UPTO_DC6;
 +
 +      WARN_ON_ONCE(state & ~mask);
 +
 +      if (i915.enable_dc == 0)
 +              state = DC_STATE_DISABLE;
 +      else if (i915.enable_dc == 1 && state > DC_STATE_EN_UPTO_DC5)
 +              state = DC_STATE_EN_UPTO_DC5;
 +
 +      if (state & DC_STATE_EN_UPTO_DC5_DC6_MASK)
 +              gen9_set_dc_state_debugmask_memory_up(dev_priv);
  
        val = I915_READ(DC_STATE_EN);
 -      val |= DC_STATE_EN_DC9;
 +      DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n",
 +                    val & mask, state);
 +      val &= ~mask;
 +      val |= state;
        I915_WRITE(DC_STATE_EN, val);
        POSTING_READ(DC_STATE_EN);
  }
  
 -void bxt_disable_dc9(struct drm_i915_private *dev_priv)
 +void bxt_enable_dc9(struct drm_i915_private *dev_priv)
  {
 -      uint32_t val;
 +      assert_can_enable_dc9(dev_priv);
 +
 +      DRM_DEBUG_KMS("Enabling DC9\n");
 +
 +      gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9);
 +}
  
 +void bxt_disable_dc9(struct drm_i915_private *dev_priv)
 +{
        assert_can_disable_dc9(dev_priv);
  
        DRM_DEBUG_KMS("Disabling DC9\n");
  
 -      val = I915_READ(DC_STATE_EN);
 -      val &= ~DC_STATE_EN_DC9;
 -      I915_WRITE(DC_STATE_EN, val);
 -      POSTING_READ(DC_STATE_EN);
 +      gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
  }
  
 -static void gen9_set_dc_state_debugmask_memory_up(
 -                      struct drm_i915_private *dev_priv)
 +static void assert_csr_loaded(struct drm_i915_private *dev_priv)
  {
 -      uint32_t val;
 -
 -      /* The below bit doesn't need to be cleared ever afterwards */
 -      val = I915_READ(DC_STATE_DEBUG);
 -      if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) {
 -              val |= DC_STATE_DEBUG_MASK_MEMORY_UP;
 -              I915_WRITE(DC_STATE_DEBUG, val);
 -              POSTING_READ(DC_STATE_DEBUG);
 -      }
 +      WARN_ONCE(!I915_READ(CSR_PROGRAM(0)),
 +                "CSR program storage start is NULL\n");
 +      WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
 +      WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
  }
  
  static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
  
  static void assert_can_disable_dc5(struct drm_i915_private *dev_priv)
  {
 -      bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv,
 -                                      SKL_DISP_PW_2);
        /*
         * During initialization, the firmware may not be loaded yet.
         * We still want to make sure that the DC enabling flag is cleared.
        if (dev_priv->power_domains.initializing)
                return;
  
 -      WARN_ONCE(!pg2_enabled, "PG2 not enabled to disable DC5.\n");
        WARN_ONCE(dev_priv->pm.suspended,
                "Disabling of DC5 while platform is runtime-suspended should never happen.\n");
  }
  
  static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
  {
 -      uint32_t val;
 -
        assert_can_enable_dc5(dev_priv);
  
        DRM_DEBUG_KMS("Enabling DC5\n");
  
 -      gen9_set_dc_state_debugmask_memory_up(dev_priv);
 -
 -      val = I915_READ(DC_STATE_EN);
 -      val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
 -      val |= DC_STATE_EN_UPTO_DC5;
 -      I915_WRITE(DC_STATE_EN, val);
 -      POSTING_READ(DC_STATE_EN);
 -}
 -
 -static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
 -{
 -      uint32_t val;
 -
 -      assert_can_disable_dc5(dev_priv);
 -
 -      DRM_DEBUG_KMS("Disabling DC5\n");
 -
 -      val = I915_READ(DC_STATE_EN);
 -      val &= ~DC_STATE_EN_UPTO_DC5;
 -      I915_WRITE(DC_STATE_EN, val);
 -      POSTING_READ(DC_STATE_EN);
 +      gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
  }
  
  static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
@@@ -523,37 -546,40 +523,37 @@@ static void assert_can_disable_dc6(stru
        if (dev_priv->power_domains.initializing)
                return;
  
 -      assert_csr_loaded(dev_priv);
        WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
                  "DC6 already programmed to be disabled.\n");
  }
  
 -static void skl_enable_dc6(struct drm_i915_private *dev_priv)
 +static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv)
  {
 -      uint32_t val;
 +      assert_can_disable_dc5(dev_priv);
 +
 +      if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1)
 +              assert_can_disable_dc6(dev_priv);
  
 +      gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 +}
 +
 +void skl_enable_dc6(struct drm_i915_private *dev_priv)
 +{
        assert_can_enable_dc6(dev_priv);
  
        DRM_DEBUG_KMS("Enabling DC6\n");
  
 -      gen9_set_dc_state_debugmask_memory_up(dev_priv);
 +      gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
  
 -      val = I915_READ(DC_STATE_EN);
 -      val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK;
 -      val |= DC_STATE_EN_UPTO_DC6;
 -      I915_WRITE(DC_STATE_EN, val);
 -      POSTING_READ(DC_STATE_EN);
  }
  
 -static void skl_disable_dc6(struct drm_i915_private *dev_priv)
 +void skl_disable_dc6(struct drm_i915_private *dev_priv)
  {
 -      uint32_t val;
 -
        assert_can_disable_dc6(dev_priv);
  
        DRM_DEBUG_KMS("Disabling DC6\n");
  
 -      val = I915_READ(DC_STATE_EN);
 -      val &= ~DC_STATE_EN_UPTO_DC6;
 -      I915_WRITE(DC_STATE_EN, val);
 -      POSTING_READ(DC_STATE_EN);
 +      gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
  }
  
  static void skl_set_power_well(struct drm_i915_private *dev_priv,
                                !I915_READ(HSW_PWR_WELL_BIOS),
                                "Invalid for power well status to be enabled, unless done by the BIOS, \
                                when request is to disable!\n");
 -                      if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
 -                              power_well->data == SKL_DISP_PW_2) {
 -                              if (SKL_ENABLE_DC6(dev)) {
 -                                      skl_disable_dc6(dev_priv);
 -                                      /*
 -                                       * DDI buffer programming unnecessary during driver-load/resume
 -                                       * as it's already done during modeset initialization then.
 -                                       * It's also invalid here as encoder list is still uninitialized.
 -                                       */
 -                                      if (!dev_priv->power_domains.initializing)
 -                                              intel_prepare_ddi(dev);
 -                              } else {
 -                                      gen9_disable_dc5(dev_priv);
 -                              }
 +                      if (power_well->data == SKL_DISP_PW_2) {
 +                              /*
 +                               * DDI buffer programming unnecessary during
 +                               * driver-load/resume as it's already done
 +                               * during modeset initialization then. It's
 +                               * also invalid here as encoder list is still
 +                               * uninitialized.
 +                               */
 +                              if (!dev_priv->power_domains.initializing)
 +                                      intel_prepare_ddi(dev);
                        }
                        I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
                }
                }
        } else {
                if (enable_requested) {
 -                      if (IS_SKYLAKE(dev) &&
 -                              (power_well->data == SKL_DISP_PW_1) &&
 -                              (intel_csr_load_status_get(dev_priv) == FW_LOADED))
 -                              DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n");
 -                      else {
 -                              I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
 -                              POSTING_READ(HSW_PWR_WELL_DRIVER);
 -                              DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
 -                      }
 -
 -                      if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
 -                              power_well->data == SKL_DISP_PW_2) {
 -                              enum csr_state state;
 -                              /* TODO: wait for a completion event or
 -                               * similar here instead of busy
 -                               * waiting using wait_for function.
 -                               */
 -                              wait_for((state = intel_csr_load_status_get(dev_priv)) !=
 -                                              FW_UNINITIALIZED, 1000);
 -                              if (state != FW_LOADED)
 -                                      DRM_DEBUG("CSR firmware not ready (%d)\n",
 -                                                      state);
 -                              else
 -                                      if (SKL_ENABLE_DC6(dev))
 -                                              skl_enable_dc6(dev_priv);
 -                                      else
 -                                              gen9_enable_dc5(dev_priv);
 -                      }
 +                      I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
 +                      POSTING_READ(HSW_PWR_WELL_DRIVER);
 +                      DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
                }
        }
  
@@@ -704,41 -759,6 +704,41 @@@ static void skl_power_well_disable(stru
        skl_set_power_well(dev_priv, power_well, false);
  }
  
 +static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
 +                                         struct i915_power_well *power_well)
 +{
 +      return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0;
 +}
 +
 +static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
 +                                        struct i915_power_well *power_well)
 +{
 +      gen9_disable_dc5_dc6(dev_priv);
 +}
 +
 +static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
 +                                         struct i915_power_well *power_well)
 +{
 +      if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1)
 +              skl_enable_dc6(dev_priv);
 +      else
 +              gen9_enable_dc5(dev_priv);
 +}
 +
 +static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv,
 +                                         struct i915_power_well *power_well)
 +{
 +      if (power_well->count > 0) {
 +              gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 +      } else {
 +              if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 &&
 +                  i915.enable_dc != 1)
 +                      gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
 +              else
 +                      gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
 +      }
 +}
 +
  static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
                                           struct i915_power_well *power_well)
  {
@@@ -953,12 -973,10 +953,12 @@@ static struct i915_power_well *lookup_p
                                                 int power_well_id)
  {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
 -      struct i915_power_well *power_well;
        int i;
  
 -      for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
 +      for (i = 0; i < power_domains->power_well_count; i++) {
 +              struct i915_power_well *power_well;
 +
 +              power_well = &power_domains->power_wells[i];
                if (power_well->data == power_well_id)
                        return power_well;
        }
@@@ -1439,7 -1457,7 +1439,7 @@@ void intel_display_power_put(struct drm
        for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
                WARN_ON(!power_well->count);
  
 -              if (!--power_well->count && i915.disable_power_well)
 +              if (!--power_well->count)
                        intel_power_well_disable(dev_priv, power_well);
        }
  
  #define HSW_ALWAYS_ON_POWER_DOMAINS (                 \
        BIT(POWER_DOMAIN_PIPE_A) |                      \
        BIT(POWER_DOMAIN_TRANSCODER_EDP) |              \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |          \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |          \
 +      BIT(POWER_DOMAIN_PORT_DDI_A_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |            \
 +      BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |            \
        BIT(POWER_DOMAIN_PORT_CRT) |                    \
        BIT(POWER_DOMAIN_PLLS) |                        \
        BIT(POWER_DOMAIN_AUX_A) |                       \
        BIT(POWER_DOMAIN_AUX_B) |                       \
        BIT(POWER_DOMAIN_AUX_C) |                       \
        BIT(POWER_DOMAIN_AUX_D) |                       \
 +      BIT(POWER_DOMAIN_GMBUS) |                       \
        BIT(POWER_DOMAIN_INIT))
  #define HSW_DISPLAY_POWER_DOMAINS (                           \
        (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) |    \
  #define VLV_DISPLAY_POWER_DOMAINS     POWER_DOMAIN_MASK
  
  #define VLV_DPIO_CMN_BC_POWER_DOMAINS (               \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |    \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |    \
        BIT(POWER_DOMAIN_PORT_CRT) |            \
        BIT(POWER_DOMAIN_AUX_B) |               \
        BIT(POWER_DOMAIN_AUX_C) |               \
        BIT(POWER_DOMAIN_INIT))
  
  #define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS (        \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |    \
        BIT(POWER_DOMAIN_AUX_B) |               \
        BIT(POWER_DOMAIN_INIT))
  
  #define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS (        \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |    \
        BIT(POWER_DOMAIN_AUX_B) |               \
        BIT(POWER_DOMAIN_INIT))
  
  #define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS (        \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |    \
        BIT(POWER_DOMAIN_AUX_C) |               \
        BIT(POWER_DOMAIN_INIT))
  
  #define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS (        \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |    \
        BIT(POWER_DOMAIN_AUX_C) |               \
        BIT(POWER_DOMAIN_INIT))
  
  #define CHV_DPIO_CMN_BC_POWER_DOMAINS (               \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_B_LANES) |    \
 +      BIT(POWER_DOMAIN_PORT_DDI_C_LANES) |    \
        BIT(POWER_DOMAIN_AUX_B) |               \
        BIT(POWER_DOMAIN_AUX_C) |               \
        BIT(POWER_DOMAIN_INIT))
  
  #define CHV_DPIO_CMN_D_POWER_DOMAINS (                \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |  \
 -      BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |  \
 +      BIT(POWER_DOMAIN_PORT_DDI_D_LANES) |    \
        BIT(POWER_DOMAIN_AUX_D) |               \
        BIT(POWER_DOMAIN_INIT))
  
@@@ -1561,13 -1589,6 +1561,13 @@@ static const struct i915_power_well_op
        .is_enabled = skl_power_well_enabled,
  };
  
 +static const struct i915_power_well_ops gen9_dc_off_power_well_ops = {
 +      .sync_hw = gen9_dc_off_power_well_sync_hw,
 +      .enable = gen9_dc_off_power_well_enable,
 +      .disable = gen9_dc_off_power_well_disable,
 +      .is_enabled = gen9_dc_off_power_well_enabled,
 +};
 +
  static struct i915_power_well hsw_power_wells[] = {
        {
                .name = "always-on",
@@@ -1623,7 -1644,6 +1623,7 @@@ static struct i915_power_well vlv_power
                .always_on = 1,
                .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
                .ops = &i9xx_always_on_power_well_ops,
 +              .data = PUNIT_POWER_WELL_ALWAYS_ON,
        },
        {
                .name = "display",
@@@ -1725,28 -1745,19 +1725,28 @@@ static struct i915_power_well skl_power
                .always_on = 1,
                .domains = SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS,
                .ops = &i9xx_always_on_power_well_ops,
 +              .data = SKL_DISP_PW_ALWAYS_ON,
        },
        {
                .name = "power well 1",
 -              .domains = SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS,
 +              /* Handled by the DMC firmware */
 +              .domains = 0,
                .ops = &skl_power_well_ops,
                .data = SKL_DISP_PW_1,
        },
        {
                .name = "MISC IO power well",
 -              .domains = SKL_DISPLAY_MISC_IO_POWER_DOMAINS,
 +              /* Handled by the DMC firmware */
 +              .domains = 0,
                .ops = &skl_power_well_ops,
                .data = SKL_DISP_PW_MISC_IO,
        },
 +      {
 +              .name = "DC off",
 +              .domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS,
 +              .ops = &gen9_dc_off_power_well_ops,
 +              .data = SKL_DISP_PW_DC_OFF,
 +      },
        {
                .name = "power well 2",
                .domains = SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS,
        },
  };
  
 +void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv)
 +{
 +      struct i915_power_well *well;
 +
 +      if (!IS_SKYLAKE(dev_priv))
 +              return;
 +
 +      well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
 +      intel_power_well_enable(dev_priv, well);
 +
 +      well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO);
 +      intel_power_well_enable(dev_priv, well);
 +}
 +
 +void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv)
 +{
 +      struct i915_power_well *well;
 +
 +      if (!IS_SKYLAKE(dev_priv))
 +              return;
 +
 +      well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
 +      intel_power_well_disable(dev_priv, well);
 +
 +      well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO);
 +      intel_power_well_disable(dev_priv, well);
 +}
 +
  static struct i915_power_well bxt_power_wells[] = {
        {
                .name = "always-on",
                .ops = &skl_power_well_ops,
                .data = SKL_DISP_PW_1,
        },
 +      {
 +              .name = "DC off",
 +              .domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS,
 +              .ops = &gen9_dc_off_power_well_ops,
 +              .data = SKL_DISP_PW_DC_OFF,
 +      },
        {
                .name = "power well 2",
                .domains = BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS,
                .ops = &skl_power_well_ops,
                .data = SKL_DISP_PW_2,
 -      }
 +      },
  };
  
+ static int
+ sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv,
+                                  int disable_power_well)
+ {
+       if (disable_power_well >= 0)
+               return !!disable_power_well;
+       if (IS_SKYLAKE(dev_priv)) {
+               DRM_DEBUG_KMS("Disabling display power well support\n");
+               return 0;
+       }
+       return 1;
+ }
  #define set_power_wells(power_domains, __power_wells) ({              \
        (power_domains)->power_wells = (__power_wells);                 \
        (power_domains)->power_well_count = ARRAY_SIZE(__power_wells);  \
@@@ -1850,8 -1842,9 +1865,11 @@@ int intel_power_domains_init(struct drm
  {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
  
+       i915.disable_power_well = sanitize_disable_power_well_option(dev_priv,
+                                                    i915.disable_power_well);
 +      BUILD_BUG_ON(POWER_DOMAIN_NUM > 31);
 +
        mutex_init(&power_domains->lock);
  
        /*
                set_power_wells(power_domains, hsw_power_wells);
        } else if (IS_BROADWELL(dev_priv->dev)) {
                set_power_wells(power_domains, bdw_power_wells);
 -      } else if (IS_SKYLAKE(dev_priv->dev)) {
 +      } else if (IS_SKYLAKE(dev_priv->dev) || IS_KABYLAKE(dev_priv->dev)) {
                set_power_wells(power_domains, skl_power_wells);
        } else if (IS_BROXTON(dev_priv->dev)) {
                set_power_wells(power_domains, bxt_power_wells);
        return 0;
  }
  
 -static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
 -{
 -      struct drm_device *dev = dev_priv->dev;
 -      struct device *device = &dev->pdev->dev;
 -
 -      if (!HAS_RUNTIME_PM(dev))
 -              return;
 -
 -      if (!intel_enable_rc6(dev))
 -              return;
 -
 -      /* Make sure we're not suspended first. */
 -      pm_runtime_get_sync(device);
 -}
 -
  /**
   * intel_power_domains_fini - finalizes the power domain structures
   * @dev_priv: i915 device instance
   */
  void intel_power_domains_fini(struct drm_i915_private *dev_priv)
  {
 -      intel_runtime_pm_disable(dev_priv);
 -
        /* The i915.ko module is still not prepared to be loaded when
         * the power well is not enabled, so just enable it in case
         * we're going to unload/reload. */
        intel_display_set_init_power(dev_priv, true);
 +
 +      /* Remove the refcount we took to keep power well support disabled. */
 +      if (!i915.disable_power_well)
 +              intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
  }
  
 -static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
 +static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
  {
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *power_well;
        mutex_unlock(&power_domains->lock);
  }
  
 +static void skl_display_core_init(struct drm_i915_private *dev_priv,
 +                                bool resume)
 +{
 +      struct i915_power_domains *power_domains = &dev_priv->power_domains;
 +      uint32_t val;
 +
 +      gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 +
 +      /* enable PCH reset handshake */
 +      val = I915_READ(HSW_NDE_RSTWRN_OPT);
 +      I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
 +
 +      /* enable PG1 and Misc I/O */
 +      mutex_lock(&power_domains->lock);
 +      skl_pw1_misc_io_init(dev_priv);
 +      mutex_unlock(&power_domains->lock);
 +
 +      if (!resume)
 +              return;
 +
 +      skl_init_cdclk(dev_priv);
 +
 +      if (dev_priv->csr.dmc_payload)
 +              intel_csr_load_program(dev_priv);
 +}
 +
 +static void skl_display_core_uninit(struct drm_i915_private *dev_priv)
 +{
 +      struct i915_power_domains *power_domains = &dev_priv->power_domains;
 +
 +      gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 +
 +      skl_uninit_cdclk(dev_priv);
 +
 +      /* The spec doesn't call for removing the reset handshake flag */
 +      /* disable PG1 and Misc I/O */
 +      mutex_lock(&power_domains->lock);
 +      skl_pw1_misc_io_fini(dev_priv);
 +      mutex_unlock(&power_domains->lock);
 +}
 +
  static void chv_phy_control_init(struct drm_i915_private *dev_priv)
  {
        struct i915_power_well *cmn_bc =
@@@ -2075,16 -2040,14 +2093,16 @@@ static void vlv_cmnlane_wa(struct drm_i
   * This function initializes the hardware power domain state and enables all
   * power domains using intel_display_set_init_power().
   */
 -void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
 +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
  {
        struct drm_device *dev = dev_priv->dev;
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
  
        power_domains->initializing = true;
  
 -      if (IS_CHERRYVIEW(dev)) {
 +      if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
 +              skl_display_core_init(dev_priv, resume);
 +      } else if (IS_CHERRYVIEW(dev)) {
                mutex_lock(&power_domains->lock);
                chv_phy_control_init(dev_priv);
                mutex_unlock(&power_domains->lock);
  
        /* For now, we need the power well to be always enabled. */
        intel_display_set_init_power(dev_priv, true);
 -      intel_power_domains_resume(dev_priv);
 +      /* Disable power support if the user asked so. */
 +      if (!i915.disable_power_well)
 +              intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
 +      intel_power_domains_sync_hw(dev_priv);
        power_domains->initializing = false;
  }
  
  /**
 - * intel_aux_display_runtime_get - grab an auxiliary power domain reference
 + * intel_power_domains_suspend - suspend power domain state
   * @dev_priv: i915 device instance
   *
 - * This function grabs a power domain reference for the auxiliary power domain
 - * (for access to the GMBUS and DP AUX blocks) and ensures that it and all its
 - * parents are powered up. Therefore users should only grab a reference to the
 - * innermost power domain they need.
 - *
 - * Any power domain reference obtained by this function must have a symmetric
 - * call to intel_aux_display_runtime_put() to release the reference again.
 + * This function prepares the hardware power domain state before entering
 + * system suspend. It must be paired with intel_power_domains_init_hw().
   */
 -void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
 +void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
  {
 -      intel_runtime_pm_get(dev_priv);
 -}
 +      if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
 +              skl_display_core_uninit(dev_priv);
  
 -/**
 - * intel_aux_display_runtime_put - release an auxiliary power domain reference
 - * @dev_priv: i915 device instance
 - *
 - * This function drops the auxiliary power domain reference obtained by
 - * intel_aux_display_runtime_get() and might power down the corresponding
 - * hardware block right away if this is the last reference.
 - */
 -void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
 -{
 -      intel_runtime_pm_put(dev_priv);
 +      /*
 +       * Even if power well support was disabled we still want to disable
 +       * power wells while we are system suspended.
 +       */
 +      if (!i915.disable_power_well)
 +              intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
  }
  
  /**
  
  #define FORCEWAKE_ACK_TIMEOUT_MS 50
  
 -#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
 -#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__))
 -
 -#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
 -#define __raw_i915_write16(dev_priv__, reg__, val__) writew(val__, (dev_priv__)->regs + (reg__))
 -
 -#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
 -#define __raw_i915_write32(dev_priv__, reg__, val__) writel(val__, (dev_priv__)->regs + (reg__))
 -
 -#define __raw_i915_read64(dev_priv__, reg__) readq((dev_priv__)->regs + (reg__))
 -#define __raw_i915_write64(dev_priv__, reg__, val__) writeq(val__, (dev_priv__)->regs + (reg__))
 -
 -#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
 +#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32((dev_priv__), (reg__))
  
  static const char * const forcewake_domain_names[] = {
        "render",
@@@ -60,7 -72,7 +60,7 @@@ assert_device_not_suspended(struct drm_
  static inline void
  fw_domain_reset(const struct intel_uncore_forcewake_domain *d)
  {
 -      WARN_ON(d->reg_set == 0);
 +      WARN_ON(!i915_mmio_reg_valid(d->reg_set));
        __raw_i915_write32(d->i915, d->reg_set, d->val_reset);
  }
  
@@@ -106,7 -118,7 +106,7 @@@ static inline voi
  fw_domain_posting_read(const struct intel_uncore_forcewake_domain *d)
  {
        /* something from same cacheline, but not from the set register */
 -      if (d->reg_post)
 +      if (i915_mmio_reg_valid(d->reg_post))
                __raw_posting_read(d->i915, d->reg_post);
  }
  
@@@ -513,7 -525,8 +513,7 @@@ void assert_forcewakes_inactive(struct 
  }
  
  /* We give fast paths for the really cool registers */
 -#define NEEDS_FORCE_WAKE(reg) \
 -       ((reg) < 0x40000 && (reg) != FORCEWAKE)
 +#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000)
  
  #define REG_RANGE(reg, start, end) ((reg) >= (start) && (reg) < (end))
  
        REG_RANGE((reg), 0x9400, 0x9800)
  
  #define FORCEWAKE_GEN9_BLITTER_RANGE_OFFSET(reg) \
 -      ((reg) < 0x40000 &&\
 +      ((reg) < 0x40000 && \
         !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) && \
         !FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg) && \
         !FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg) && \
@@@ -592,8 -605,8 +592,8 @@@ ilk_dummy_write(struct drm_i915_privat
  }
  
  static void
 -hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read,
 -                      bool before)
 +hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv,
 +                      i915_reg_t reg, bool read, bool before)
  {
        const char *op = read ? "reading" : "writing to";
        const char *when = before ? "before" : "after";
  
        if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) {
                WARN(1, "Unclaimed register detected %s %s register 0x%x\n",
 -                   when, op, reg);
 +                   when, op, i915_mmio_reg_offset(reg));
                __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
                i915.mmio_debug--; /* Only report the first N failures */
        }
@@@ -636,7 -649,7 +636,7 @@@ hsw_unclaimed_reg_detect(struct drm_i91
  
  #define __gen2_read(x) \
  static u##x \
 -gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 +gen2_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
        GEN2_READ_HEADER(x); \
        val = __raw_i915_read##x(dev_priv, reg); \
        GEN2_READ_FOOTER; \
  
  #define __gen5_read(x) \
  static u##x \
 -gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 +gen5_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
        GEN2_READ_HEADER(x); \
        ilk_dummy_write(dev_priv); \
        val = __raw_i915_read##x(dev_priv, reg); \
@@@ -667,7 -680,6 +667,7 @@@ __gen2_read(64
  #undef GEN2_READ_HEADER
  
  #define GEN6_READ_HEADER(x) \
 +      u32 offset = i915_mmio_reg_offset(reg); \
        unsigned long irqflags; \
        u##x val = 0; \
        assert_device_not_suspended(dev_priv); \
@@@ -702,12 -714,20 +702,12 @@@ static inline void __force_wake_get(str
                dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
  }
  
 -#define __vgpu_read(x) \
 -static u##x \
 -vgpu_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 -      GEN6_READ_HEADER(x); \
 -      val = __raw_i915_read##x(dev_priv, reg); \
 -      GEN6_READ_FOOTER; \
 -}
 -
  #define __gen6_read(x) \
  static u##x \
 -gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 +gen6_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
        GEN6_READ_HEADER(x); \
        hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
 -      if (NEEDS_FORCE_WAKE(reg)) \
 +      if (NEEDS_FORCE_WAKE(offset)) \
                __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
        val = __raw_i915_read##x(dev_priv, reg); \
        hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
  
  #define __vlv_read(x) \
  static u##x \
 -vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 +vlv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 +      enum forcewake_domains fw_engine = 0; \
        GEN6_READ_HEADER(x); \
 -      if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) \
 -              __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
 -      else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) \
 -              __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
 +      if (!NEEDS_FORCE_WAKE(offset)) \
 +              fw_engine = 0; \
 +      else if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_RENDER; \
 +      else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_MEDIA; \
 +      if (fw_engine) \
 +              __force_wake_get(dev_priv, fw_engine); \
        val = __raw_i915_read##x(dev_priv, reg); \
        GEN6_READ_FOOTER; \
  }
  
  #define __chv_read(x) \
  static u##x \
 -chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 +chv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 +      enum forcewake_domains fw_engine = 0; \
        GEN6_READ_HEADER(x); \
 -      if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
 -              __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
 -      else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
 -              __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
 -      else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
 -              __force_wake_get(dev_priv, \
 -                               FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
 +      if (!NEEDS_FORCE_WAKE(offset)) \
 +              fw_engine = 0; \
 +      else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_RENDER; \
 +      else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_MEDIA; \
 +      else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
 +      if (fw_engine) \
 +              __force_wake_get(dev_priv, fw_engine); \
        val = __raw_i915_read##x(dev_priv, reg); \
        GEN6_READ_FOOTER; \
  }
  
  #define SKL_NEEDS_FORCE_WAKE(reg) \
 -       ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
 +      ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
  
  #define __gen9_read(x) \
  static u##x \
 -gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 +gen9_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
        enum forcewake_domains fw_engine; \
        GEN6_READ_HEADER(x); \
        hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
 -      if (!SKL_NEEDS_FORCE_WAKE(reg)) \
 +      if (!SKL_NEEDS_FORCE_WAKE(offset)) \
                fw_engine = 0; \
 -      else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
 +      else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \
                fw_engine = FORCEWAKE_RENDER; \
 -      else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
 +      else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \
                fw_engine = FORCEWAKE_MEDIA; \
 -      else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
 +      else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \
                fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
        else \
                fw_engine = FORCEWAKE_BLITTER; \
        GEN6_READ_FOOTER; \
  }
  
 -__vgpu_read(8)
 -__vgpu_read(16)
 -__vgpu_read(32)
 -__vgpu_read(64)
  __gen9_read(8)
  __gen9_read(16)
  __gen9_read(32)
@@@ -797,37 -812,10 +797,37 @@@ __gen6_read(64
  #undef __chv_read
  #undef __vlv_read
  #undef __gen6_read
 -#undef __vgpu_read
  #undef GEN6_READ_FOOTER
  #undef GEN6_READ_HEADER
  
 +#define VGPU_READ_HEADER(x) \
 +      unsigned long irqflags; \
 +      u##x val = 0; \
 +      assert_device_not_suspended(dev_priv); \
 +      spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
 +
 +#define VGPU_READ_FOOTER \
 +      spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
 +      trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
 +      return val
 +
 +#define __vgpu_read(x) \
 +static u##x \
 +vgpu_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \
 +      VGPU_READ_HEADER(x); \
 +      val = __raw_i915_read##x(dev_priv, reg); \
 +      VGPU_READ_FOOTER; \
 +}
 +
 +__vgpu_read(8)
 +__vgpu_read(16)
 +__vgpu_read(32)
 +__vgpu_read(64)
 +
 +#undef __vgpu_read
 +#undef VGPU_READ_FOOTER
 +#undef VGPU_READ_HEADER
 +
  #define GEN2_WRITE_HEADER \
        trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
        assert_device_not_suspended(dev_priv); \
  
  #define __gen2_write(x) \
  static void \
 -gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 +gen2_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
        GEN2_WRITE_HEADER; \
        __raw_i915_write##x(dev_priv, reg, val); \
        GEN2_WRITE_FOOTER; \
  
  #define __gen5_write(x) \
  static void \
 -gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 +gen5_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
        GEN2_WRITE_HEADER; \
        ilk_dummy_write(dev_priv); \
        __raw_i915_write##x(dev_priv, reg, val); \
@@@ -867,7 -855,6 +867,7 @@@ __gen2_write(64
  #undef GEN2_WRITE_HEADER
  
  #define GEN6_WRITE_HEADER \
 +      u32 offset = i915_mmio_reg_offset(reg); \
        unsigned long irqflags; \
        trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
        assert_device_not_suspended(dev_priv); \
  
  #define __gen6_write(x) \
  static void \
 -gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 +gen6_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
        u32 __fifo_ret = 0; \
        GEN6_WRITE_HEADER; \
 -      if (NEEDS_FORCE_WAKE(reg)) { \
 +      if (NEEDS_FORCE_WAKE(offset)) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
        __raw_i915_write##x(dev_priv, reg, val); \
  
  #define __hsw_write(x) \
  static void \
 -hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 +hsw_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
        u32 __fifo_ret = 0; \
        GEN6_WRITE_HEADER; \
 -      if (NEEDS_FORCE_WAKE(reg)) { \
 +      if (NEEDS_FORCE_WAKE(offset)) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
        hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
        GEN6_WRITE_FOOTER; \
  }
  
 -#define __vgpu_write(x) \
 -static void vgpu_write##x(struct drm_i915_private *dev_priv, \
 -                        off_t reg, u##x val, bool trace) { \
 -      GEN6_WRITE_HEADER; \
 -      __raw_i915_write##x(dev_priv, reg, val); \
 -      GEN6_WRITE_FOOTER; \
 -}
 -
 -static const u32 gen8_shadowed_regs[] = {
 +static const i915_reg_t gen8_shadowed_regs[] = {
        FORCEWAKE_MT,
        GEN6_RPNSWREQ,
        GEN6_RC_VIDEO_FREQ,
        /* TODO: Other registers are not yet used */
  };
  
 -static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
 +static bool is_gen8_shadowed(struct drm_i915_private *dev_priv,
 +                           i915_reg_t reg)
  {
        int i;
        for (i = 0; i < ARRAY_SIZE(gen8_shadowed_regs); i++)
 -              if (reg == gen8_shadowed_regs[i])
 +              if (i915_mmio_reg_equal(reg, gen8_shadowed_regs[i]))
                        return true;
  
        return false;
  
  #define __gen8_write(x) \
  static void \
 -gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 +gen8_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
        GEN6_WRITE_HEADER; \
        hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
 -      if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) \
 +      if (NEEDS_FORCE_WAKE(offset) && !is_gen8_shadowed(dev_priv, reg)) \
                __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
        __raw_i915_write##x(dev_priv, reg, val); \
        hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
  
  #define __chv_write(x) \
  static void \
 -chv_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 -      bool shadowed = is_gen8_shadowed(dev_priv, reg); \
 +chv_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \
 +      enum forcewake_domains fw_engine = 0; \
        GEN6_WRITE_HEADER; \
 -      if (!shadowed) { \
 -              if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
 -                      __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
 -              else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
 -                      __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
 -              else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
 -                      __force_wake_get(dev_priv, FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
 -      } \
 +      if (!NEEDS_FORCE_WAKE(offset) || \
 +          is_gen8_shadowed(dev_priv, reg)) \
 +              fw_engine = 0; \
 +      else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_RENDER; \
 +      else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_MEDIA; \
 +      else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \
 +              fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
 +      if (fw_engine) \
 +              __force_wake_get(dev_priv, fw_engine); \
        __raw_i915_write##x(dev_priv, reg, val); \
        GEN6_WRITE_FOOTER; \
  }
  
 -static const u32 gen9_shadowed_regs[] = {
 +static const i915_reg_t gen9_shadowed_regs[] = {
        RING_TAIL(RENDER_RING_BASE),
        RING_TAIL(GEN6_BSD_RING_BASE),
        RING_TAIL(VEBOX_RING_BASE),
        /* TODO: Other registers are not yet used */
  };
  
 -static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg)
 +static bool is_gen9_shadowed(struct drm_i915_private *dev_priv,
 +                           i915_reg_t reg)
  {
        int i;
        for (i = 0; i < ARRAY_SIZE(gen9_shadowed_regs); i++)
 -              if (reg == gen9_shadowed_regs[i])
 +              if (i915_mmio_reg_equal(reg, gen9_shadowed_regs[i]))
                        return true;
  
        return false;
  
  #define __gen9_write(x) \
  static void \
 -gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
 +gen9_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, \
                bool trace) { \
        enum forcewake_domains fw_engine; \
        GEN6_WRITE_HEADER; \
        hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
 -      if (!SKL_NEEDS_FORCE_WAKE(reg) || \
 +      if (!SKL_NEEDS_FORCE_WAKE(offset) || \
            is_gen9_shadowed(dev_priv, reg)) \
                fw_engine = 0; \
 -      else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
 +      else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \
                fw_engine = FORCEWAKE_RENDER; \
 -      else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
 +      else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \
                fw_engine = FORCEWAKE_MEDIA; \
 -      else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
 +      else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \
                fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
        else \
                fw_engine = FORCEWAKE_BLITTER; \
@@@ -1034,41 -1024,20 +1034,41 @@@ __gen6_write(8
  __gen6_write(16)
  __gen6_write(32)
  __gen6_write(64)
 -__vgpu_write(8)
 -__vgpu_write(16)
 -__vgpu_write(32)
 -__vgpu_write(64)
  
  #undef __gen9_write
  #undef __chv_write
  #undef __gen8_write
  #undef __hsw_write
  #undef __gen6_write
 -#undef __vgpu_write
  #undef GEN6_WRITE_FOOTER
  #undef GEN6_WRITE_HEADER
  
 +#define VGPU_WRITE_HEADER \
 +      unsigned long irqflags; \
 +      trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
 +      assert_device_not_suspended(dev_priv); \
 +      spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
 +
 +#define VGPU_WRITE_FOOTER \
 +      spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
 +
 +#define __vgpu_write(x) \
 +static void vgpu_write##x(struct drm_i915_private *dev_priv, \
 +                        i915_reg_t reg, u##x val, bool trace) { \
 +      VGPU_WRITE_HEADER; \
 +      __raw_i915_write##x(dev_priv, reg, val); \
 +      VGPU_WRITE_FOOTER; \
 +}
 +
 +__vgpu_write(8)
 +__vgpu_write(16)
 +__vgpu_write(32)
 +__vgpu_write(64)
 +
 +#undef __vgpu_write
 +#undef VGPU_WRITE_FOOTER
 +#undef VGPU_WRITE_HEADER
 +
  #define ASSIGN_WRITE_MMIO_VFUNCS(x) \
  do { \
        dev_priv->uncore.funcs.mmio_writeb = x##_write8; \
@@@ -1088,8 -1057,7 +1088,8 @@@ do { 
  
  static void fw_domain_init(struct drm_i915_private *dev_priv,
                           enum forcewake_domain_id domain_id,
 -                         u32 reg_set, u32 reg_ack)
 +                         i915_reg_t reg_set,
 +                         i915_reg_t reg_ack)
  {
        struct intel_uncore_forcewake_domain *d;
  
                d->reg_post = FORCEWAKE_ACK_VLV;
        else if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv) || IS_GEN8(dev_priv))
                d->reg_post = ECOBUS;
 -      else
 -              d->reg_post = 0;
  
        d->i915 = dev_priv;
        d->id = domain_id;
@@@ -1292,14 -1262,12 +1292,14 @@@ void intel_uncore_fini(struct drm_devic
  #define GEN_RANGE(l, h) GENMASK(h, l)
  
  static const struct register_whitelist {
 -      uint64_t offset;
 +      i915_reg_t offset_ldw, offset_udw;
        uint32_t size;
        /* supported gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
        uint32_t gen_bitmask;
  } whitelist[] = {
 -      { RING_TIMESTAMP(RENDER_RING_BASE), 8, GEN_RANGE(4, 9) },
 +      { .offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE),
 +        .offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE),
 +        .size = 8, .gen_bitmask = GEN_RANGE(4, 9) },
  };
  
  int i915_reg_read_ioctl(struct drm_device *dev,
        struct drm_i915_reg_read *reg = data;
        struct register_whitelist const *entry = whitelist;
        unsigned size;
 -      u64 offset;
 +      i915_reg_t offset_ldw, offset_udw;
        int i, ret = 0;
  
        for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
 -              if (entry->offset == (reg->offset & -entry->size) &&
 +              if (i915_mmio_reg_offset(entry->offset_ldw) == (reg->offset & -entry->size) &&
                    (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
                        break;
        }
         * be naturally aligned (and those that are not so aligned merely
         * limit the available flags for that register).
         */
 -      offset = entry->offset;
 +      offset_ldw = entry->offset_ldw;
 +      offset_udw = entry->offset_udw;
        size = entry->size;
 -      size |= reg->offset ^ offset;
 +      size |= reg->offset ^ i915_mmio_reg_offset(offset_ldw);
  
        intel_runtime_pm_get(dev_priv);
  
        switch (size) {
        case 8 | 1:
 -              reg->val = I915_READ64_2x32(offset, offset+4);
 +              reg->val = I915_READ64_2x32(offset_ldw, offset_udw);
                break;
        case 8:
 -              reg->val = I915_READ64(offset);
 +              reg->val = I915_READ64(offset_ldw);
                break;
        case 4:
 -              reg->val = I915_READ(offset);
 +              reg->val = I915_READ(offset_ldw);
                break;
        case 2:
 -              reg->val = I915_READ16(offset);
 +              reg->val = I915_READ16(offset_ldw);
                break;
        case 1:
 -              reg->val = I915_READ8(offset);
 +              reg->val = I915_READ8(offset_ldw);
                break;
        default:
                ret = -EINVAL;
@@@ -1503,7 -1470,7 +1503,7 @@@ static int gen6_do_reset(struct drm_dev
  }
  
  static int wait_for_register(struct drm_i915_private *dev_priv,
 -                           const u32 reg,
 +                           i915_reg_t reg,
                             const u32 mask,
                             const u32 value,
                             const unsigned long timeout_ms)
@@@ -1564,13 -1531,22 +1564,22 @@@ static int (*intel_get_gpu_reset(struc
  
  int intel_gpu_reset(struct drm_device *dev)
  {
+       struct drm_i915_private *dev_priv = to_i915(dev);
        int (*reset)(struct drm_device *);
+       int ret;
  
        reset = intel_get_gpu_reset(dev);
        if (reset == NULL)
                return -ENODEV;
  
-       return reset(dev);
+       /* If the power well sleeps during the reset, the reset
+        * request may be dropped and never completes (causing -EIO).
+        */
+       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+       ret = reset(dev);
+       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+       return ret;
  }
  
  bool intel_has_gpu_reset(struct drm_device *dev)
diff --combined drivers/pci/quirks.c
@@@ -2246,6 -2246,7 +2246,7 @@@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_V
  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
  DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
  
  /* Disable MSI on chipsets that are known to not support it */
  static void quirk_disable_msi(struct pci_dev *dev)
@@@ -3404,9 -3405,7 +3405,9 @@@ static int reset_intel_82599_sfp_virtfn
        return 0;
  }
  
 -#include "../gpu/drm/i915/i915_reg.h"
 +#define SOUTH_CHICKEN2                0xc2004
 +#define PCH_PP_STATUS         0xc7200
 +#define PCH_PP_CONTROL                0xc7204
  #define MSG_CTL                       0x45010
  #define NSDE_PWR_STATE                0xd0100
  #define IGD_OPERATION_TIMEOUT 10000     /* set timeout 10 seconds */
@@@ -3709,6 -3708,63 +3710,63 @@@ DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0
  DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6869, PCI_CLASS_NOT_DEFINED, 8,
                              quirk_tw686x_class);
  
+ /*
+  * Per PCIe r3.0, sec 2.2.9, "Completion headers must supply the same
+  * values for the Attribute as were supplied in the header of the
+  * corresponding Request, except as explicitly allowed when IDO is used."
+  *
+  * If a non-compliant device generates a completion with a different
+  * attribute than the request, the receiver may accept it (which itself
+  * seems non-compliant based on sec 2.3.2), or it may handle it as a
+  * Malformed TLP or an Unexpected Completion, which will probably lead to a
+  * device access timeout.
+  *
+  * If the non-compliant device generates completions with zero attributes
+  * (instead of copying the attributes from the request), we can work around
+  * this by disabling the "Relaxed Ordering" and "No Snoop" attributes in
+  * upstream devices so they always generate requests with zero attributes.
+  *
+  * This affects other devices under the same Root Port, but since these
+  * attributes are performance hints, there should be no functional problem.
+  *
+  * Note that Configuration Space accesses are never supposed to have TLP
+  * Attributes, so we're safe waiting till after any Configuration Space
+  * accesses to do the Root Port fixup.
+  */
+ static void quirk_disable_root_port_attributes(struct pci_dev *pdev)
+ {
+       struct pci_dev *root_port = pci_find_pcie_root_port(pdev);
+       if (!root_port) {
+               dev_warn(&pdev->dev, "PCIe Completion erratum may cause device errors\n");
+               return;
+       }
+       dev_info(&root_port->dev, "Disabling No Snoop/Relaxed Ordering Attributes to avoid PCIe Completion erratum in %s\n",
+                dev_name(&pdev->dev));
+       pcie_capability_clear_and_set_word(root_port, PCI_EXP_DEVCTL,
+                                          PCI_EXP_DEVCTL_RELAX_EN |
+                                          PCI_EXP_DEVCTL_NOSNOOP_EN, 0);
+ }
+ /*
+  * The Chelsio T5 chip fails to copy TLP Attributes from a Request to the
+  * Completion it generates.
+  */
+ static void quirk_chelsio_T5_disable_root_port_attributes(struct pci_dev *pdev)
+ {
+       /*
+        * This mask/compare operation selects for Physical Function 4 on a
+        * T5.  We only need to fix up the Root Port once for any of the
+        * PFs.  PF[0..3] have PCI Device IDs of 0x50xx, but PF4 is uniquely
+        * 0x54xx so we use that one,
+        */
+       if ((pdev->device & 0xff00) == 0x5400)
+               quirk_disable_root_port_attributes(pdev);
+ }
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+                        quirk_chelsio_T5_disable_root_port_attributes);
  /*
   * AMD has indicated that the devices below do not support peer-to-peer
   * in any system where they are found in the southbridge with an AMD