drm/doc: Rename docbook to gpu.tmpl
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 7 Oct 2015 07:55:28 +0000 (09:55 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 16 Oct 2015 13:50:57 +0000 (15:50 +0200)
DRM is a lot more than a direct rendering manager nowadays, and there's
also a bunch of things worth documenting for gpu driver developers
outside of drivers/gpu/drm, like vgaarb, vga_switcheroo or the various
hardware buses like host1x and ipu-v3.

To avoid further confusion let's rename the top-level to reflect
reality.

And yes I'm already looking forward to when we need to replace the G
in GPU with a * ;-)

Inspired by a thread with Lukas since he refused to include the
vga_switcheroo docs into the drm docs because it's not drm.

Cc: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
[Lukas: Drop BUG() easter egg in i915_gem_execbuffer.c spotted by Jani
and fix typos in commit message.]
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Acked-by: Dave Airlie <airlied@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Documentation/DocBook/Makefile
Documentation/DocBook/drm.tmpl [deleted file]
Documentation/DocBook/gpu.tmpl [new file with mode: 0644]

index 93eff64387cd2324f3f0731ffaba1bca9f39cfb9..810f466238d3bbee7bf1f05d198277f6f9c5e082 100644 (file)
@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
-           tracepoint.xml drm.xml media_api.xml w1.xml \
+           tracepoint.xml gpu.xml media_api.xml w1.xml \
            writing_musb_glue_layer.xml crypto-API.xml iio.xml
 
 include Documentation/DocBook/media/Makefile
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
deleted file mode 100644 (file)
index 2bc6c80..0000000
+++ /dev/null
@@ -1,4203 +0,0 @@
-<?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="drmDevelopersGuide">
-  <bookinfo>
-    <title>Linux DRM 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>
-    </authorgroup>
-
-    <copyright>
-      <year>2008-2009</year>
-      <year>2013-2014</year>
-      <holder>Intel Corporation</holder>
-    </copyright>
-    <copyright>
-      <year>2012</year>
-      <holder>Laurent Pinchart</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>
-    </revhistory>
-  </bookinfo>
-
-<toc></toc>
-
-<part id="drmCore">
-  <title>DRM Core</title>
-  <partintro>
-    <para>
-      This first part of the DRM 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. 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 DRM 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
-      </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> 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>
-</book>
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl
new file mode 100644 (file)
index 0000000..48e3ab4
--- /dev/null
@@ -0,0 +1,4203 @@
+<?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="drmDevelopersGuide">
+  <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>
+    </authorgroup>
+
+    <copyright>
+      <year>2008-2009</year>
+      <year>2013-2014</year>
+      <holder>Intel Corporation</holder>
+    </copyright>
+    <copyright>
+      <year>2012</year>
+      <holder>Laurent Pinchart</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>
+    </revhistory>
+  </bookinfo>
+
+<toc></toc>
+
+<part id="drmCore">
+  <title>DRM Core</title>
+  <partintro>
+    <para>
+      This first part of the DRM 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. 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 DRM 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
+      </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> 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>
+</book>