| <?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> | 
 |  | 
 |     <copyright> | 
 |       <year>2008-2009</year> | 
 |       <holder> | 
 | 	Intel Corporation (Jesse Barnes <jesse.barnes@intel.com>) | 
 |       </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> | 
 |   </bookinfo> | 
 |  | 
 | <toc></toc> | 
 |  | 
 |   <!-- Introduction --> | 
 |  | 
 |   <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 can 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'll go over some typical driver initialization | 
 |       requirements, like setting up command buffers, creating an | 
 |       initial output configuration, and initializing core services. | 
 |       Subsequent sections will 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 & fencing, suspend/resume support, and DMA | 
 |       services. | 
 |     </para> | 
 |     <para> | 
 |       The core of every DRM driver is struct drm_driver.  Drivers | 
 |       will typically statically initialize a drm_driver structure, | 
 |       then pass it to drm_init() at load time. | 
 |     </para> | 
 |  | 
 |   <!-- Internals: driver init --> | 
 |  | 
 |   <sect1> | 
 |     <title>Driver initialization</title> | 
 |     <para> | 
 |       Before calling the DRM initialization routines, the driver must | 
 |       first create and fill out a struct drm_driver structure. | 
 |     </para> | 
 |     <programlisting> | 
 |       static struct drm_driver driver = { | 
 | 	/* don't use mtrr's here, the Xserver or user space app should | 
 | 	 * deal with them for intel hardware. | 
 | 	 */ | 
 | 	.driver_features = | 
 | 	    DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | | 
 | 	    DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_MODESET, | 
 | 	.load = i915_driver_load, | 
 | 	.unload = i915_driver_unload, | 
 | 	.firstopen = i915_driver_firstopen, | 
 | 	.lastclose = i915_driver_lastclose, | 
 | 	.preclose = i915_driver_preclose, | 
 | 	.save = i915_save, | 
 | 	.restore = i915_restore, | 
 | 	.device_is_agp = i915_driver_device_is_agp, | 
 | 	.get_vblank_counter = i915_get_vblank_counter, | 
 | 	.enable_vblank = i915_enable_vblank, | 
 | 	.disable_vblank = i915_disable_vblank, | 
 | 	.irq_preinstall = i915_driver_irq_preinstall, | 
 | 	.irq_postinstall = i915_driver_irq_postinstall, | 
 | 	.irq_uninstall = i915_driver_irq_uninstall, | 
 | 	.irq_handler = i915_driver_irq_handler, | 
 | 	.reclaim_buffers = drm_core_reclaim_buffers, | 
 | 	.get_map_ofs = drm_core_get_map_ofs, | 
 | 	.get_reg_ofs = drm_core_get_reg_ofs, | 
 | 	.fb_probe = intelfb_probe, | 
 | 	.fb_remove = intelfb_remove, | 
 | 	.fb_resize = intelfb_resize, | 
 | 	.master_create = i915_master_create, | 
 | 	.master_destroy = i915_master_destroy, | 
 | #if defined(CONFIG_DEBUG_FS) | 
 | 	.debugfs_init = i915_debugfs_init, | 
 | 	.debugfs_cleanup = i915_debugfs_cleanup, | 
 | #endif | 
 | 	.gem_init_object = i915_gem_init_object, | 
 | 	.gem_free_object = i915_gem_free_object, | 
 | 	.gem_vm_ops = &i915_gem_vm_ops, | 
 | 	.ioctls = i915_ioctls, | 
 | 	.fops = { | 
 | 		.owner = THIS_MODULE, | 
 | 		.open = drm_open, | 
 | 		.release = drm_release, | 
 | 		.ioctl = drm_ioctl, | 
 | 		.mmap = drm_mmap, | 
 | 		.poll = drm_poll, | 
 | 		.fasync = drm_fasync, | 
 | #ifdef CONFIG_COMPAT | 
 | 		.compat_ioctl = i915_compat_ioctl, | 
 | #endif | 
 | 		.llseek = noop_llseek, | 
 | 		}, | 
 | 	.pci_driver = { | 
 | 		.name = DRIVER_NAME, | 
 | 		.id_table = pciidlist, | 
 | 		.probe = probe, | 
 | 		.remove = __devexit_p(drm_cleanup_pci), | 
 | 		}, | 
 | 	.name = DRIVER_NAME, | 
 | 	.desc = DRIVER_DESC, | 
 | 	.date = DRIVER_DATE, | 
 | 	.major = DRIVER_MAJOR, | 
 | 	.minor = DRIVER_MINOR, | 
 | 	.patchlevel = DRIVER_PATCHLEVEL, | 
 |       }; | 
 |     </programlisting> | 
 |     <para> | 
 |       In the example above, taken from the i915 DRM driver, the driver | 
 |       sets several flags indicating what core features it supports. | 
 |       We'll go over the individual callbacks in later sections.  Since | 
 |       flags indicate which features your driver supports to the DRM | 
 |       core, you need to set most of them prior to calling drm_init().  Some, | 
 |       like DRIVER_MODESET can be set later based on user supplied parameters, | 
 |       but that's the exception rather than the rule. | 
 |     </para> | 
 |     <variablelist> | 
 |       <title>Driver flags</title> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_USE_AGP</term> | 
 | 	<listitem><para> | 
 | 	    Driver uses AGP interface | 
 | 	</para></listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_REQUIRE_AGP</term> | 
 | 	<listitem><para> | 
 | 	    Driver needs AGP interface to function. | 
 | 	</para></listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_USE_MTRR</term> | 
 | 	<listitem> | 
 | 	  <para> | 
 | 	    Driver uses MTRR interface for mapping memory.  Deprecated. | 
 | 	  </para> | 
 | 	</listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_PCI_DMA</term> | 
 | 	<listitem><para> | 
 | 	    Driver is capable of PCI DMA.  Deprecated. | 
 | 	</para></listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_SG</term> | 
 | 	<listitem><para> | 
 | 	    Driver can perform scatter/gather DMA.  Deprecated. | 
 | 	</para></listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_HAVE_DMA</term> | 
 | 	<listitem><para>Driver supports DMA.  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 a IRQ | 
 | 	    handler, DRIVER_IRQ_SHARED indicates whether the device & | 
 | 	    handler support shared IRQs (note that this is required of | 
 | 	    PCI drivers). | 
 | 	  </para> | 
 | 	</listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_DMA_QUEUE</term> | 
 | 	<listitem> | 
 | 	  <para> | 
 | 	    If the driver queues DMA requests and completes them | 
 | 	    asynchronously, this flag should be set.  Deprecated. | 
 | 	  </para> | 
 | 	</listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_FB_DMA</term> | 
 | 	<listitem> | 
 | 	  <para> | 
 | 	    Driver supports DMA to/from the framebuffer.  Deprecated. | 
 | 	  </para> | 
 | 	</listitem> | 
 |       </varlistentry> | 
 |       <varlistentry> | 
 | 	<term>DRIVER_MODESET</term> | 
 | 	<listitem> | 
 | 	  <para> | 
 | 	    Driver supports mode setting interfaces. | 
 | 	  </para> | 
 | 	</listitem> | 
 |       </varlistentry> | 
 |     </variablelist> | 
 |     <para> | 
 |       In this specific case, the driver requires AGP and supports | 
 |       IRQs.  DMA, as we'll see, is handled by device specific ioctls | 
 |       in this case.  It also supports the kernel mode setting APIs, though | 
 |       unlike in the actual i915 driver source, this example unconditionally | 
 |       exports KMS capability. | 
 |     </para> | 
 |   </sect1> | 
 |  | 
 |   <!-- Internals: driver load --> | 
 |  | 
 |   <sect1> | 
 |     <title>Driver load</title> | 
 |     <para> | 
 |       In the previous section, we saw what a typical drm_driver | 
 |       structure might look like.  One of the more important fields in | 
 |       the structure is the hook for the load function. | 
 |     </para> | 
 |     <programlisting> | 
 |       static struct drm_driver driver = { | 
 |       	... | 
 |       	.load = i915_driver_load, | 
 |         ... | 
 |       }; | 
 |     </programlisting> | 
 |     <para> | 
 |       The load function has many responsibilities: allocating a driver | 
 |       private structure, specifying supported performance counters, | 
 |       configuring the device (e.g. mapping registers & command | 
 |       buffers), initializing the memory manager, and setting up the | 
 |       initial output configuration. | 
 |     </para> | 
 |     <para> | 
 |       Note that the tasks performed at driver load time must not | 
 |       conflict with DRM client requirements.  For instance, if user | 
 |       level mode setting drivers are in use, it would be problematic | 
 |       to perform output discovery & configuration at load time. | 
 |       Likewise, if pre-memory management aware user level drivers are | 
 |       in use, memory management and command buffer setup may need to | 
 |       be omitted.  These requirements are driver specific, and care | 
 |       needs to be taken to keep both old and new applications and | 
 |       libraries working.  The i915 driver supports the "modeset" | 
 |       module parameter to control whether advanced features are | 
 |       enabled at load time or in legacy fashion.  If compatibility is | 
 |       a concern (e.g. with drivers converted over to the new interfaces | 
 |       from the old ones), care must be taken to prevent incompatible | 
 |       device initialization and control with the currently active | 
 |       userspace drivers. | 
 |     </para> | 
 |  | 
 |     <sect2> | 
 |       <title>Driver private & performance counters</title> | 
 |       <para> | 
 | 	The driver private hangs off the main drm_device structure and | 
 | 	can be used for tracking various device specific bits of | 
 | 	information, like register offsets, command buffer status, | 
 | 	register state for suspend/resume, etc.  At load time, a | 
 | 	driver can simply allocate one and set drm_device.dev_priv | 
 | 	appropriately; at unload the driver can free it and set | 
 | 	drm_device.dev_priv to NULL. | 
 |       </para> | 
 |       <para> | 
 | 	The DRM supports several counters which can be used for rough | 
 | 	performance characterization.  Note that the DRM stat counter | 
 | 	system is not often used by applications, and supporting | 
 | 	additional counters is completely optional. | 
 |       </para> | 
 |       <para> | 
 | 	These interfaces are deprecated and should not be used.  If performance | 
 | 	monitoring is desired, the developer should investigate and | 
 | 	potentially enhance the kernel perf and tracing infrastructure to export | 
 | 	GPU related performance information to performance monitoring | 
 | 	tools and applications. | 
 |       </para> | 
 |     </sect2> | 
 |  | 
 |     <sect2> | 
 |       <title>Configuring the device</title> | 
 |       <para> | 
 | 	Obviously, device configuration will be device specific. | 
 | 	However, there are several common operations: finding a | 
 | 	device's PCI resources, mapping them, and potentially setting | 
 | 	up an IRQ handler. | 
 |       </para> | 
 |       <para> | 
 | 	Finding & mapping resources is fairly straightforward.  The | 
 | 	DRM wrapper functions, drm_get_resource_start() and | 
 | 	drm_get_resource_len() can be used to find BARs on the given | 
 | 	drm_device struct.  Once those values have been retrieved, the | 
 | 	driver load function can call drm_addmap() to create a new | 
 | 	mapping for the BAR in question.  Note you'll probably want a | 
 | 	drm_local_map_t in your driver private structure to track any | 
 | 	mappings you create. | 
 | <!-- !Fdrivers/gpu/drm/drm_bufs.c drm_get_resource_* --> | 
 | <!-- !Finclude/drm/drmP.h drm_local_map_t --> | 
 |       </para> | 
 |       <para> | 
 | 	if compatibility with other operating systems isn't a concern | 
 | 	(DRM drivers can run under various BSD variants and OpenSolaris), | 
 | 	native Linux calls can be used for the above, e.g. pci_resource_* | 
 | 	and iomap*/iounmap.  See the Linux device driver book for more | 
 | 	info. | 
 |       </para> | 
 |       <para> | 
 | 	Once you have a register map, you can use the DRM_READn() and | 
 | 	DRM_WRITEn() macros to access the registers on your device, or | 
 | 	use driver specific versions to offset into your MMIO space | 
 | 	relative to a driver specific base pointer (see I915_READ for | 
 | 	example). | 
 |       </para> | 
 |       <para> | 
 | 	If your device supports interrupt generation, you may want to | 
 | 	setup an interrupt handler at driver load time as well.  This | 
 | 	is done using the drm_irq_install() function.  If your device | 
 | 	supports vertical blank interrupts, it should call | 
 | 	drm_vblank_init() to initialize the core vblank handling code before | 
 | 	enabling interrupts on your device.  This ensures the vblank related | 
 | 	structures are allocated and allows the core to handle vblank events. | 
 |       </para> | 
 | <!--!Fdrivers/char/drm/drm_irq.c drm_irq_install--> | 
 |       <para> | 
 | 	Once your interrupt handler is registered (it'll use your | 
 | 	drm_driver.irq_handler as the actual interrupt handling | 
 | 	function), you can safely enable interrupts on your device, | 
 | 	assuming any other state your interrupt handler uses is also | 
 | 	initialized. | 
 |       </para> | 
 |       <para> | 
 | 	Another task that may be necessary 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 once you've | 
 | 	mapped the ROM and extracted any necessary information, be | 
 | 	sure to unmap it; on many devices the ROM address decoder is | 
 | 	shared with other BARs, so leaving it mapped can cause | 
 | 	undesired behavior like hangs or memory corruption. | 
 | <!--!Fdrivers/pci/rom.c pci_map_rom--> | 
 |       </para> | 
 |     </sect2> | 
 |  | 
 |     <sect2> | 
 |       <title>Memory manager initialization</title> | 
 |       <para> | 
 | 	In order to allocate command buffers, cursor memory, scanout | 
 | 	buffers, etc., as well as support the latest features provided | 
 | 	by packages like Mesa and the X.Org X server, your driver | 
 | 	should support a memory manager. | 
 |       </para> | 
 |       <para> | 
 | 	If your driver supports memory management (it should!), you'll | 
 | 	need to set that up at load time as well.  How you initialize | 
 | 	it depends on which memory manager you're using, TTM or GEM. | 
 |       </para> | 
 |       <sect3> | 
 | 	<title>TTM initialization</title> | 
 | 	<para> | 
 | 	  TTM (for Translation Table Manager) manages video memory and | 
 | 	  aperture space for graphics devices. TTM supports both UMA devices | 
 | 	  and devices with dedicated video RAM (VRAM), i.e. most discrete | 
 | 	  graphics devices.  If your device has dedicated RAM, supporting | 
 | 	  TTM is desirable.  TTM also integrates tightly with your | 
 | 	  driver specific buffer execution function.  See the radeon | 
 | 	  driver for examples. | 
 | 	</para> | 
 | 	<para> | 
 | 	  The core TTM structure is the ttm_bo_driver struct.  It 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 will 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 | 
 | 	  (done by calling ttm_global_item_ref on the global object you | 
 | 	  just created), you'll 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 can 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> | 
 |       <sect3> | 
 | 	<title>GEM initialization</title> | 
 | 	<para> | 
 | 	  GEM is an alternative to TTM, designed specifically for UMA | 
 | 	  devices.  It has simpler initialization and execution requirements | 
 | 	  than TTM, but has no VRAM management capability.  Core GEM | 
 | 	  initialization is comprised of a basic drm_mm_init call to create | 
 | 	  a GTT DRM MM object, which provides an address space pool for | 
 | 	  object allocation.  In a KMS configuration, the driver will | 
 | 	  need to allocate and initialize a command ring buffer following | 
 | 	  basic GEM initialization.  Most UMA devices have a so-called | 
 | 	  "stolen" memory region, which provides space for the initial | 
 | 	  framebuffer and large, contiguous memory regions required by the | 
 | 	  device.  This space is not typically managed by GEM, and must | 
 | 	  be initialized separately into its own DRM MM object. | 
 | 	</para> | 
 | 	<para> | 
 | 	  Initialization will be driver specific, and will depend on | 
 | 	  the architecture of the device.  In the case of Intel | 
 | 	  integrated graphics chips like 965GM, GEM initialization can | 
 | 	  be done by calling the internal GEM init function, | 
 | 	  i915_gem_do_init().  Since the 965GM is a UMA device | 
 | 	  (i.e. it doesn't have dedicated VRAM), GEM will manage | 
 | 	  making regular RAM available for GPU operations.  Memory set | 
 | 	  aside by the BIOS (called "stolen" memory by the i915 | 
 | 	  driver) will be managed by the DRM memrange allocator; the | 
 | 	  rest of the aperture will be managed by GEM. | 
 | 	  <programlisting> | 
 | 	    /* Basic memrange allocator for stolen space (aka vram) */ | 
 | 	    drm_memrange_init(&dev_priv->vram, 0, prealloc_size); | 
 | 	    /* Let GEM Manage from end of prealloc space to end of aperture */ | 
 | 	    i915_gem_do_init(dev, prealloc_size, agp_size); | 
 | 	  </programlisting> | 
 | <!--!Edrivers/char/drm/drm_memrange.c--> | 
 | 	</para> | 
 | 	<para> | 
 | 	  Once the memory manager has been set up, we can allocate the | 
 | 	  command buffer.  In the i915 case, this is also done with a | 
 | 	  GEM function, i915_gem_init_ringbuffer(). | 
 | 	</para> | 
 |       </sect3> | 
 |     </sect2> | 
 |  | 
 |     <sect2> | 
 |       <title>Output configuration</title> | 
 |       <para> | 
 | 	The final initialization task is output configuration.  This involves | 
 | 	finding and initializing the CRTCs, encoders and connectors | 
 | 	for your device, creating an initial configuration and | 
 | 	registering a framebuffer console driver. | 
 |       </para> | 
 |       <sect3> | 
 | 	<title>Output discovery and initialization</title> | 
 | 	<para> | 
 | 	  Several core functions exist to create CRTCs, encoders and | 
 | 	  connectors, namely drm_crtc_init(), drm_connector_init() and | 
 | 	  drm_encoder_init(), along with several "helper" functions to | 
 | 	  perform common tasks. | 
 | 	</para> | 
 | 	<para> | 
 | 	  Connectors should be registered with sysfs once they've been | 
 | 	  detected and initialized, using the | 
 | 	  drm_sysfs_connector_add() function.  Likewise, when they're | 
 | 	  removed from the system, they should be destroyed with | 
 | 	  drm_sysfs_connector_remove(). | 
 | 	</para> | 
 | 	<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_sysfs_connector_add(connector); | 
 | } | 
 | ]]> | 
 | 	</programlisting> | 
 | 	<para> | 
 | 	  In the example above (again, taken from the i915 driver), a | 
 | 	  CRT 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> | 
 | 	<sect4> | 
 | 	  <title>Helper functions and core functions</title> | 
 | 	  <para> | 
 | 	    Since many PC-class graphics devices have similar display output | 
 | 	    designs, the DRM provides a set of helper functions to make | 
 | 	    output management easier.  The core helper routines handle | 
 | 	    encoder re-routing and disabling of unused functions following | 
 | 	    mode set.  Using the helpers is optional, but recommended for | 
 | 	    devices with PC-style architectures (i.e. a set of display planes | 
 | 	    for feeding pixels to encoders which are in turn routed to | 
 | 	    connectors).  Devices with more complex requirements needing | 
 | 	    finer grained management can opt to use the core callbacks | 
 | 	    directly. | 
 | 	  </para> | 
 | 	  <para> | 
 | 	    [Insert typical diagram here.]  [Insert OMAP style config here.] | 
 | 	  </para> | 
 | 	</sect4> | 
 | 	<para> | 
 | 	  For each encoder, CRTC and connector, several functions must | 
 | 	  be provided, depending on the object type.  Encoder objects | 
 | 	  need to provide a DPMS (basically on/off) function, mode fixup | 
 | 	  (for converting requested modes into native hardware timings), | 
 | 	  and prepare, set and commit functions for use by the core DRM | 
 | 	  helper functions.  Connector helpers need to provide mode fetch and | 
 | 	  validity functions as well as an encoder matching function for | 
 | 	  returning an ideal encoder for a given connector.  The core | 
 | 	  connector functions include a DPMS callback, (deprecated) | 
 | 	  save/restore routines, detection, mode probing, property handling, | 
 | 	  and cleanup functions. | 
 | 	</para> | 
 | <!--!Edrivers/char/drm/drm_crtc.h--> | 
 | <!--!Edrivers/char/drm/drm_crtc.c--> | 
 | <!--!Edrivers/char/drm/drm_crtc_helper.c--> | 
 |       </sect3> | 
 |     </sect2> | 
 |   </sect1> | 
 |  | 
 |   <!-- Internals: vblank handling --> | 
 |  | 
 |   <sect1> | 
 |     <title>VBlank event handling</title> | 
 |     <para> | 
 |       The DRM core exposes two vertical blank related ioctls: | 
 |       DRM_IOCTL_WAIT_VBLANK and DRM_IOCTL_MODESET_CTL. | 
 | <!--!Edrivers/char/drm/drm_irq.c--> | 
 |     </para> | 
 |     <para> | 
 |       DRM_IOCTL_WAIT_VBLANK takes a struct drm_wait_vblank structure | 
 |       as its argument, and is used to block or request a signal when a | 
 |       specified vblank event occurs. | 
 |     </para> | 
 |     <para> | 
 |       DRM_IOCTL_MODESET_CTL should be called by application level | 
 |       drivers before and after mode setting, since on many devices the | 
 |       vertical blank counter will be reset at that time.  Internally, | 
 |       the DRM snapshots the last vblank count when the ioctl is called | 
 |       with the _DRM_PRE_MODESET command so that the counter won't go | 
 |       backwards (which is dealt with when _DRM_POST_MODESET is used). | 
 |     </para> | 
 |     <para> | 
 |       To support the functions above, the DRM core provides several | 
 |       helper functions for tracking vertical blank counters, and | 
 |       requires drivers to provide several callbacks: | 
 |       get_vblank_counter(), enable_vblank() and disable_vblank().  The | 
 |       core uses get_vblank_counter() to keep the counter accurate | 
 |       across interrupt disable periods.  It should return the current | 
 |       vertical blank event count, which is often tracked in a device | 
 |       register.  The enable and disable vblank callbacks should enable | 
 |       and disable vertical blank interrupts, respectively.  In the | 
 |       absence of DRM clients waiting on vblank events, the core DRM | 
 |       code will use the disable_vblank() function to disable | 
 |       interrupts, which saves power.  They'll be re-enabled again when | 
 |       a client calls the vblank wait ioctl above. | 
 |     </para> | 
 |     <para> | 
 |       Devices that don't provide a count register can simply use an | 
 |       internal atomic counter incremented on every vertical blank | 
 |       interrupt, and can make their enable and disable vblank | 
 |       functions into no-ops. | 
 |     </para> | 
 |   </sect1> | 
 |  | 
 |   <sect1> | 
 |     <title>Memory management</title> | 
 |     <para> | 
 |       The memory manager lies at the heart of many DRM operations, and | 
 |       is also required to support advanced client features like OpenGL | 
 |       pbuffers.  The DRM currently contains two memory managers, TTM | 
 |       and GEM. | 
 |     </para> | 
 |  | 
 |     <sect2> | 
 |       <title>The Translation Table Manager (TTM)</title> | 
 |       <para> | 
 | 	TTM was developed by Tungsten Graphics, primarily by Thomas | 
 | 	Hellström, and is intended to be a flexible, high performance | 
 | 	graphics memory manager. | 
 |       </para> | 
 |       <para> | 
 | 	Drivers wishing to support TTM must fill out a drm_bo_driver | 
 | 	structure. | 
 |       </para> | 
 |       <para> | 
 | 	TTM design background and information belongs here. | 
 |       </para> | 
 |     </sect2> | 
 |  | 
 |     <sect2> | 
 |       <title>The Graphics Execution Manager (GEM)</title> | 
 |       <para> | 
 | 	GEM is an Intel project, authored by Eric Anholt and Keith | 
 | 	Packard.  It provides simpler interfaces than TTM, and is well | 
 | 	suited for UMA devices. | 
 |       </para> | 
 |       <para> | 
 | 	GEM-enabled drivers must provide gem_init_object() and | 
 | 	gem_free_object() callbacks to support the core memory | 
 | 	allocation routines.  They should also provide several driver | 
 | 	specific ioctls to support command execution, pinning, buffer | 
 | 	read & write, mapping, and domain ownership transfers. | 
 |       </para> | 
 |       <para> | 
 | 	On a fundamental level, GEM involves several operations: memory | 
 | 	allocation and freeing, command execution, and aperture management | 
 | 	at command execution time.  Buffer object allocation is relatively | 
 | 	straightforward and largely provided by Linux's shmem layer, which | 
 | 	provides memory to back each object.  When mapped into the GTT | 
 | 	or used in a command buffer, the backing pages for an object are | 
 | 	flushed to memory and marked write combined so as to be coherent | 
 | 	with the GPU.  Likewise, when the GPU finishes rendering to an object, | 
 | 	if the CPU accesses it, it must be made coherent with the CPU's view | 
 | 	of memory, usually involving GPU cache flushing of various kinds. | 
 | 	This core CPU<->GPU coherency management is provided by the GEM | 
 | 	set domain function, 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 the set domain function | 
 | 	will block the client and wait for rendering to complete before | 
 | 	performing any necessary flushing operations). | 
 |       </para> | 
 |       <para> | 
 | 	Perhaps the most important GEM function is providing a command | 
 | 	execution interface to clients.  Client programs construct command | 
 | 	buffers containing references to previously allocated memory objects | 
 | 	and submit them to GEM.  At that point, GEM will take 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 or 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> | 
 |     </sect2> | 
 |  | 
 |   </sect1> | 
 |  | 
 |   <!-- Output management --> | 
 |   <sect1> | 
 |     <title>Output management</title> | 
 |     <para> | 
 |       At the core of the DRM output management code is a set of | 
 |       structures representing CRTCs, encoders and connectors. | 
 |     </para> | 
 |     <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, 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> | 
 |     <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> | 
 |     <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 & | 
 |       connection status, and information about modes supported on the | 
 |       attached displays. | 
 |     </para> | 
 | <!--!Edrivers/char/drm/drm_crtc.c--> | 
 |   </sect1> | 
 |  | 
 |   <sect1> | 
 |     <title>Framebuffer management</title> | 
 |     <para> | 
 |       In order to set a mode on a given CRTC, encoder and connector | 
 |       configuration, clients need to provide a framebuffer object which | 
 |       will provide a source of pixels for the CRTC to deliver to the encoder(s) | 
 |       and ultimately the connector(s) in the configuration.  A framebuffer | 
 |       is fundamentally a driver specific memory object, made into an opaque | 
 |       handle by the DRM addfb function.  Once an fb has been created this | 
 |       way it can be passed to the KMS mode setting routines for use in | 
 |       a configuration. | 
 |     </para> | 
 |   </sect1> | 
 |  | 
 |   <sect1> | 
 |     <title>Command submission & fencing</title> | 
 |     <para> | 
 |       This should cover a few device specific command submission | 
 |       implementations. | 
 |     </para> | 
 |   </sect1> | 
 |  | 
 |   <sect1> | 
 |     <title>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 will be 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> | 
 |   </sect1> | 
 |  | 
 |   <sect1> | 
 |     <title>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> | 
 |   </sect1> | 
 |   </chapter> | 
 |  | 
 |   <!-- 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 & 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.  Only need high | 
 |       level info, since man pages will cover the rest. | 
 |     </para> | 
 |   </chapter> | 
 |  | 
 |   <!-- API reference --> | 
 |  | 
 |   <appendix id="drmDriverApi"> | 
 |     <title>DRM Driver API</title> | 
 |     <para> | 
 |       Include auto-generated API reference here (need to reference it | 
 |       from paragraphs above too). | 
 |     </para> | 
 |   </appendix> | 
 |  | 
 | </book> |