\documentclass[obeyspaces,spaces,hyphens,dvipsnames]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{minted}
\usepackage{hyperref}

\mode<presentation>
\usetheme{Bootlin}

\newcommand{\codehack}[1]{{\usebeamercolor[fg]{code} {\tt #1}}}

\title{The DRM/KMS subsystem from a newbie's point of view}
\authors{Boris Brezillon}
\institute{Bootlin}

\setcounter{tocdepth}{2}

\begin{document}

\begin{frame}
  \begin{center}
    \huge
    The DRM/KMS subsystem from a newbie's point of view
    \includegraphics[height=0.60\textheight]{linux-penguin-screen.jpg}
  \end{center}
\end{frame}

\begin{frame}{Boris Brezillon}
  \begin{itemize}
  \item Embedded Linux engineer and trainer at Bootlin
    \begin{itemize}
    \item Embedded Linux and Android {\bf development}: kernel and driver
      development, system integration, boot time and power
      consumption optimization, consulting, etc.
    \item Embedded Linux, Linux driver development, Android system and
      Yocto/OpenEmbedded {\bf training courses}, with materials freely
      available under a Creative Commons license.
    \item \url{http://bootlin.com}
    \end{itemize}
  \item Contributions
    \begin{itemize}
    \item {\bf Kernel support for the AT91 SoCs} ARM SoCs from Atmel
    \item {\bf Kernel support for the sunXi SoCs} ARM SoCs from Allwinner
    \end{itemize}
  \item Living in {\bf Toulouse}, south west of France
  \end{itemize}
\end{frame}

\AtBeginSection
{
}

\AtBeginSubsection
{
}

\begin{frame}{Agenda}
\tableofcontents
\end{frame}

\section{Context description}
\subsection{What is this talk about?}

\begin{frame}{Context: What is this talk about?}
  \begin{itemize}
  \item Sharing my understanding of the DRM/KMS subsytem learned while
        working on the Atmel HLCDC driver
  \item Explaining some key aspects (from my point of view) of the
        DRM/KMS subsystem
  \item Explaining some common concepts in the video/graphic
        world and showing how they are implemented in DRM/KMS
  \item Sharing some tips on how to develop a KMS driver based on my
        experience
  \item This talk is not:
    \begin{itemize}
    \item A detailed description of the DRM/KMS subsystem
    \item A description on how to use a DRM device (user-space API)
    \item And most importantly: this talk is not given by an expert
    \end{itemize}
  \item Don't hesitate to correct me if you think I'm wrong ;-)
  \end{itemize}
\end{frame}

\subsection{How to display things in Linux?}

\begin{frame}{Context: How to display things in the Linux world}
  \begin{itemize}
  \item Different solutions, provided by different subsystems:
    \begin{itemize}
    \item FBDEV: Framebuffer Device
    \item DRM/KMS: Direct Rendering Manager / Kernel Mode Setting
    \item V4L2: Video For Linux 2
    \end{itemize}
  \item How to choose one: it depends on your needs
    \begin{itemize}
    \item Each subsytem provides its own set of features
    \item Different levels of complexity
    \item Different levels of activity
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Context: Why choosing DRM/KMS?}
  \begin{itemize}
  \item Actively maintained
  \item Provides fine grained control on the display pipeline
  \item Widely used by user-space graphic stacks
  \item Provides a full set of advanced features
  \item Why not FBDEV?
    \begin{itemize}
    \item Less actively maintained
    \item Does not provides all the features we needed (overlays, hw cursor,
	  ...)
    \item Developers are now encouraged to move to DRM/KMS
    \end{itemize}
  \item Why not V4L2?
    \begin{itemize}
    \item Well suited for video capture and specific video output devices
	  but not for "complex" display controllers
    \end{itemize}
  \end{itemize}
\end{frame}

\section {DRM/KMS overview}
\subsection {Global architecture}

\begin{frame}{DRM/KMS: Definition}
  \begin{itemize}
  \item DRM stands for Direct Rendering Manager and was introduced
        to deal with graphic cards embedding GPUs
  \item KMS stands for Kernel Mode Setting and is a sub-part of the
        DRM API
  \item Though rendering and mode setting are now split in two
        different APIs (accessible through \code{/dev/dri/renderX} and
	\code{/dev/dri/controlDX})
  \item KMS provide a way to configure the display pipeline of a
        graphic card (or an embedded system)
  \item KMS is what we're interested in when looking for an FBDEV
        alternative
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS: Architecture}
  \begin{center}
    \includegraphics[height=0.7\textheight]{kms-vs-fbdev-display.pdf}
  \end{center}
\end{frame}

\subsection {Partial description of the components}

\begin{frame}{DRM/KMS Components: Framebuffer}
  \begin{itemize}
  \item This is a standard object storing information about the content
        to be displayed
  \item Information stored:
    \begin{itemize}
    \item References to memory regions used to store display content
    \item Format of the frames stored in memory
    \item Active area within the memory region (content that will
          displayed)
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS Components: Framebuffer}
  \begin{itemize}
  \item DRM Framebuffer is a virtual object (relies on a specific
	implementation)
  \item Framebuffer implementation depends on:
    \begin{itemize}
    \item The memory manager in use (GEM or TTM)
    \item The display controller capabilities:
     \begin{itemize}
      \item Supported DMA transfer types (Contiguous Memory or Scatter Gather)
      \item IOMMU
      \end{itemize}
    \end{itemize}
  \item Default implementation available for GEM objects using CMA (Contiguous
        Memory Allocator): \kfile{drivers/gpu/drm/drm_fb_cma_helper.c}
  \item Other implementations usually depend on the Display Controller
    \begin{itemize}
    \item Scatter Gather example: \kdir{drivers/gpu/drm/tegra}
    \item IOMMU example: \kdir{drivers/gpu/drm/exynos}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Framebuffer}
  \begin{columns}
    \begin{column}{.55\textwidth}
    \includegraphics[height=0.55\textheight]{framebuffer-fields.pdf}
    \end{column}
    \begin{column}{.40\textwidth}
    \footnotesize
      \begin{block}{}
        \begin{minted}{c}
struct drm_framebuffer {
[...]
  unsigned int pitches[4];
  unsigned int offsets[4];
  unsigned int width;
  unsigned int height;
[...]
};
        \end{minted}
      \end{block}
    \normalsize
    \end{column}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Framebuffer}
  \begin{itemize}
  \footnotesize
  \begin{block}{}
    \begin{minted}{c}
struct drm_framebuffer {
[...]
  uint32_t pixel_format; /* fourcc format */
[...]
};
    \end{minted}
  \end{block}
  \normalsize
  \item \code{pixel_format} describes the memory buffer organization
  \item Uses FOURCC format codes
  \item Supported formats are defined here: \kfile{include/drm/drm_fourcc.h}
  \item These FOURCC formats are not standardized and are thus only
        valid within the DRM/KMS subsystem
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Framebuffer}
  \begin{itemize}
  \item Three types of formats used by the DRM/KMS subsystem:
    \begin{itemize}
    \item RGB: Each pixel is encoded with an RGB tuple (a specific
          value for each component)
    \item YUV: Same thing but with Y, U and V components
    \item C8: Uses a conversion table to map a value to an RGB tuple
    \end{itemize}
  \item YUV support different modes:
    \begin{itemize}
    \item Packed: One memory region storing all components (Y, U
          and V)
    \item Semiplanar: One memory region for Y component and one for
          UV components
    \item Planar: One memory region for each component
    \end{itemize}
  \item Each memory region storing a frame component (Y, U or V) is
        called a {\em plane}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Framebuffer}
  \begin{columns}
    \begin{column}{.55\textwidth}
      \begin{itemize}
      \item Packed formats: only the first offsets and pitches entries are
            used
      \item Semiplanar formats: the first two entries are used
      \item Planar: the first 3 entries are used
      \item Don't know what the fourth entry used is for (alpha plane?)
      \end{itemize}
    \end{column}
    \begin{column}{.40\textwidth}
    \footnotesize
      \begin{block}{}
        \begin{minted}{c}
struct drm_framebuffer {
[...]
  unsigned int pitches[4];
  unsigned int offsets[4];
[...]
};
        \end{minted}
      \end{block}
    \normalsize
    \end{column}
  \end{columns}
\end{frame}

\begin{frame}{DRM/KMS Components: CRTC}
  \begin{center}
    \includegraphics[height=0.35\textheight]{kms-display-crtc.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC}
  \begin{itemize}
  \item CRTC stands for CRT Controller, though it's not only related
        to CRT displays
  \item Configure the appropriate display settings:
    \begin{itemize}
    \item Display timings
    \item Display resolution
    \end{itemize}
  \item Scan out frame buffer content to one or more displays
  \item Update the frame buffer
  \item Implemented through \kstruct{drm_crtc_funcs} and
        \kstruct{drm_crtc_helper_funcs}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
struct drm_crtc_funcs {
[...]
  int (*set_config)(struct drm_mode_set *set);
  int (*page_flip)(struct drm_crtc *crtc,
          struct drm_framebuffer *fb,
          struct drm_pending_vblank_event *event, uint32_t flags);
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (mode setting)}
  \begin{itemize}
  \item \code{set_config()} is responsible for configuring several things:
    \begin{itemize}
    \item Update the frame buffer being scanned out
    \item Configure the display mode: timings, resolution, ...
    \item Attach connectors/encoders to the CRTC
    \end{itemize}
  \item Use \kfunc{drm_crtc_helper_set_config} function and implement
        \kstruct{drm_crtc_helper_funcs} unless you really know
        what you're doing
  \footnotesize
    \begin{block}{}
      \begin{minted}{c}
struct drm_crtc_helper_funcs {
[...]
  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);
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS Components: CRTC (display timings)}
  \begin{itemize}
  \item How display content is updated hasn't changed much since the creation
        of CRT monitors (though technology has evolved)
  \item Requires at least 3 signals:
    \begin{itemize}
    \item Pixel Clock: drive the pixel stream (1 pixel updated per clock
          cycle)
    \item VSYNC: Vertical Synchronisation signal, asserted at the beginning
          of each frame
    \item HSYNC: Horizontal Synchronisation signal, asserted at the beginning
          of each pixel line
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS Components: CRTC (display timings)}
  \begin{itemize}
  \item HSYNC pulse is used to inform the display it should go to the
        next pixel line
  \item VSYNC pulse is used to inform the display it should start to
        display a new frame and thus go back to the first line
  \item What's done during the VSYNC and HSYNC pulses depends on the
        display technology
  \item Front and back porch timings are reserved time around the sync
        pulses. Action taken during these periods also depends on the
        display technology
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS Components: CRTC (display timings)}
  \begin{center}
  \includegraphics[height=0.8\textheight]{display-timings2.png}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (display timings)}
  \begin{center}
    \includegraphics[height=0.8\textheight]{kms-display-timings.png}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (mode setting)}
  \begin{center}
    \includegraphics[height=0.8\textheight]{mode-set-coordinates.png}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (mode setting)}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
				     struct drm_display_mode *mode,
				     struct drm_display_mode *adj,
				     int x, int y,
				     struct drm_framebuffer *old_fb)
{
  /* Initialize local variables */
  struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
  [...]

  /* Do some checks on the requested mode */
  if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
    return -EINVAL;

  /* Convert DRM display timings into controller specific ones */
  vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
  [...]

  /* Configure controller timings */
  regmap_write(regmap, ATMEL_HLCDC_CFG(1), (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
  [...]

  /* Update primary plane attached to the CRTC */
  fb = plane->fb;
  plane->fb = old_fb;

  return plane->funcs->update_plane(plane, c, fb, 0, 0, adj->hdisplay, adj->vdisplay,
                                    x << 16, y << 16, adj->hdisplay << 16,
                                    adj->vdisplay << 16);
}
      \end{minted}
    \end{block}
  \normalsize
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (page flipping)}
  \begin{center}
    \includegraphics[height=0.8\textheight]{page-flipping.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (page flipping)}
  \begin{itemize}
  \item \code{page_flip()} is responsible for queueing a frame update
  \footnotesize
    \begin{block}{}
      \begin{minted}{c}
struct drm_crtc_funcs {
[...]
  int (*page_flip)(struct drm_crtc *crtc,
                   struct drm_framebuffer *fb,
                   struct drm_pending_vblank_event *event,
                   uint32_t flags);
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \item The frame is really updated at the next VBLANK (interval between 2
        frames)
  \item Only one page flip at a time
  \item Should return \code{-}\ksym{EBUSY} if a page flip is already queued
  \item \code{event} is used to inform the user when page flip is
        done (the 2 frames are actually flipped)
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: CRTC (page flipping)}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c, struct drm_framebuffer *fb,
                                      struct drm_pending_vblank_event *event,
                                      uint32_t page_flip_flags)
{
  /* Initialize local variables */
  struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
  [...]

  /* Check if a there's a pending page flip request */
  spin_lock_irqsave(&dev->event_lock, flags);
  if (crtc->event)
    ret = -EBUSY;
  spin_unlock_irqrestore(&dev->event_lock, flags);
  if (ret)
    return ret;
  [...]

  /* Store the event to inform the caller when the page flip is finished */
  if (event) {
    drm_vblank_get(c->dev, crtc->id);
    spin_lock_irqsave(&dev->event_lock, flags);
    crtc->event = event;
    spin_unlock_irqrestore(&dev->event_lock, flags);
  }

  /* Queue a primary plane update request */
  ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
  [...]

  return ret;
}
      \end{minted}
    \end{block}
  \normalsize
\end{frame}

\begin{frame}{DRM/KMS Components: Planes}
  \begin{center}
    \includegraphics[height=0.35\textheight]{kms-display-plane.pdf}
  \end{center}
\end{frame}


\begin{frame}{DRM/KMS Components: Planes}
  \begin{itemize}
  \item A plane is an image layer ({\bf Be careful}: not related to the planes
        referenced by a framebuffer)
  \item The final image displayed by the CRTC is the composition of
        one or several planes
  \item Different plane types:
    \begin{itemize}
    \item \code{DRM_PLANE_TYPE_PRIMARY} (mandatory, 1 per CRTC)
      \begin{itemize}
      \item Used by the CRTC to store its frame buffer
      \item Typically used to display a background image or graphics content
      \end{itemize}
    \item \code{DRM_PLANE_TYPE_CURSOR} (optional, 1 per CRTC)
      \begin{itemize}
      \item Used to display a cursor (like a mouse cursor)
      \end{itemize}
    \item \code{DRM_PLANE_TYPE_OVERLAY} (optional, 0 to N per CRTC)
      \begin{itemize}
      \item Used to benefit from hardware composition
      \item Typically used to display windows with dynamic content (like
            a video)
      \item In case of multiple CRTCs in the display controller, the
            overlay planes can often be dynamically attached to a specific
	    CRTC when required
      \end{itemize}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS Components: Planes}
  \begin{center}
    \includegraphics[height=0.60\textheight]{kms-plane.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Planes}
  \begin{itemize}
  \item Plane support implemented through \kstruct{drm_plane_funcs}
  \footnotesize
    \begin{block}{}
      \begin{minted}{c}
struct drm_plane_funcs {
[...]
  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);
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Planes (update)}
  \begin{center}
    \includegraphics[height=0.8\textheight]{plane-update-coordinates.png}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Planes (update)}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
static int atmel_hlcdc_plane_update(struct drm_plane *p,
                                    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)
{
  struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  struct atmel_hlcdc_plane_update_req req;
  int ret = 0;

  /* Fill update request with informations passed in arguments */
  memset(&req, 0, sizeof(req));
  req.crtc_x = crtc_x;
  req.crtc_y = crtc_y;
  [...]

  /* Prepare a plane update request: reserve resources, check request
     coherency, ... */
  ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req);
  if (ret)
    return ret;
  [...]

  /* Queue the plane update request: update DMA transfers at the next
     VBLANK event */
  return atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
}
      \end{minted}
    \end{block}
  \normalsize
\end{frame}

\begin{frame}{DRM/KMS Components: Connector}
  \begin{center}
    \includegraphics[height=0.35\textheight]{kms-display-connector.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Connector}
  \begin{itemize}
  \item Represent a display connector (HDMI, DP, VGA, DVI, ...)
  \item Transmit the signals to the display
  \item Detect display connection/removal
  \item Expose display supported modes
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Connector}
  \begin{itemize}
  \item Implemented through \kstruct{drm_connector_funcs}
        and \kstruct{drm_connector_helper_funcs}
  \footnotesize
    \begin{block}{}
      \begin{minted}{c}
struct drm_connector_helper_funcs {
  int (*get_modes)(struct drm_connector *connector);
  enum drm_mode_status
      (*mode_valid)(struct drm_connector *connector,
                     struct drm_display_mode *mode);
  struct drm_encoder *
      (*best_encoder)(struct drm_connector *connector);
};
      \end{minted}
    \end{block}
    \begin{block}{}
      \begin{minted}{c}
struct drm_connector_funcs {
[...]
  enum drm_connector_status
      (*detect)(struct drm_connector *connector, bool force);
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Connector (get modes)}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector)
{
  struct rcar_du_lvds_connector *lvdscon = to_rcar_lvds_connector(connector);
  struct drm_display_mode *mode;

  /* Create a drm_display_mode */
  mode = drm_mode_create(connector->dev);
  if (mode == NULL)
    return 0;

  /* Fill the mode with the appropriate timings and flags */
  mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
  mode->clock = lvdscon->panel->mode.clock;
  mode->hdisplay = lvdscon->panel->mode.hdisplay;
  [...]

  /* Give this name a name based on the resolution: e.g. 800x600 */
  drm_mode_set_name(mode);

  /* Add this mode to the connector list */
  drm_mode_probed_add(connector, mode);

  /* Return the number of added modes */
  return 1;
}
      \end{minted}
    \end{block}
  \normalsize
\end{frame}

\begin{frame}{DRM/KMS Components: Encoder}
  \begin{center}
    \includegraphics[height=0.35\textheight]{kms-display-encoder.pdf}
  \end{center}
\end{frame}

\begin{frame}{DRM/KMS Components: Encoder}
  \begin{itemize}
  \item Directly related to the Connector concept
  \item Responsible for converting a frame into the appropriate
        format to be transmitted through the connector
  \item Example: HDMI connector is transmiting TMDS encoded data,
        and thus needs a TMDS encoder.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: Encoder}
  \begin{itemize}
  \item Implemented through \kstruct{drm_encoder_funcs}
        and \kstruct{drm_encoder_helper_funcs}
  \footnotesize
    \begin{block}{}
      \begin{minted}{c}
struct drm_encoder_helper_funcs {
[...]
  bool (*mode_fixup)(struct drm_encoder *encoder,
                     const struct drm_display_mode *mode,
                     struct drm_display_mode *adjusted_mode);
[...]
  void (*mode_set)(struct drm_encoder *encoder,
                   struct drm_display_mode *mode,
                   struct drm_display_mode *adjusted_mode);
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \end{itemize}
\end{frame}

\begin{frame}{DRM/KMS Components: DRM device}
  \begin{center}
    \includegraphics[height=0.35\textheight]{kms-display.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: DRM device}
  \begin{itemize}
  \item Responsible for aggregating the other components
  \item Device exposed to userspace (handles all user-space requests)
  \item Implemented through \kstruct{drm_driver}
  \footnotesize
    \begin{block}{}
      \begin{minted}{c}
struct drm_driver {
  int (*load) (struct drm_device *, unsigned long flags);
[...]
  int (*unload) (struct drm_device *);
[...]
  u32 driver_features;
[...]
};
      \end{minted}
    \end{block}
  \normalsize
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: DRM device}
  \begin{itemize}
  \item Call \kfunc{drm_dev_alloc} then \kfunc{drm_dev_register} to register
        a DRM device
  \item \code{load()} and \code{unload()} are responsible for instantiating and
        destroying the DRM components attached to a DRM device
  \item \code{driver_features} should contain \code{DRIVER_RENDER},
        \code{DRIVER_MODESET} or both depending on the DRM device features
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: DRM device}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
static struct drm_driver atmel_hlcdc_dc_driver = {
  .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
  .load = atmel_hlcdc_dc_load,
  .unload = atmel_hlcdc_dc_unload,
[...]
  .name = "atmel-hlcdc",
  .desc = "Atmel HLCD Controller DRM",
  .date = "20141504",
  .major = 1,
  .minor = 0,
};
      \end{minted}
    \end{block}
  \normalsize
\end{frame}

\begin{frame}[fragile]{DRM/KMS Components: DRM device}
  \tiny
    \begin{block}{}
      \begin{minted}{c}
static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
{
  struct drm_device *ddev;
  int ret;

  ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
  if (!ddev)
    return -ENOMEM;

  ret = drm_dev_set_unique(ddev, dev_name(ddev->dev));
  if (ret) {
    drm_dev_unref(ddev);
    return ret;
  }

  ret = drm_dev_register(ddev, 0);
  if (ret) {
    drm_dev_unref(ddev);
    return ret;
  }

  return 0;
}
      \end{minted}
    \end{block}
  \normalsize
\end{frame}

\begin{frame}{DRM/KMS Components: Other concepts}
  \begin{itemize}
  \item DPMS: Display Power Management Signaling
  \item Properties: transversal concept used to expose display pipeline behaviors
    \begin{itemize}
    \item Can be attached to all the components we've seen so far
    \item Examples:
      \begin{itemize}
      \item Rotation is a plane property
      \item EDID (Unique display ID exposed by a monitor) is a connector
            property
      \item ...
      \end{itemize}
    \end{itemize}
  \item Bridge: represents an external encoder accessible through a bus (i2c)
  \item Encoder slave: pretty much the same thing (still don't get the difference)
  \item FBDEV emulation
  \item Multiple CRTCs, Encoders and Connectors
  \item Other concepts I'm not aware of yet :-)
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{DRM/KMS Sequence Diagram: Mode Setting}
  \begin{center}
    \includegraphics[height=0.90\textheight]{mode-set-sequence-diagram.pdf}
  \end{center}
\end{frame}

\section{Sharing my experience}
\subsection{Tips on developing a DRM/KMS driver}

\begin{frame}{KMS Driver: Development Tips}
  \begin{itemize}
  \item Read the documentation: \kerneldochtml{gpu/drm-kms}
  \item Take a look at other drivers
    \begin{itemize}
    \item Choose a similar driver (in terms of capabilities)
    \item Check that the driver you are basing your work on is recent and
	  well maintained
    \end{itemize}
  \item Check for new features: the DRM subsystem is constantly evolving
  \item Use helper functions and structures as much as possible
  \item Start small/simple and add new features iteratively (e.g. only
	one primary plane and one encoder/connector pair)
  \item Use simple user-space tools to test it like \code{modetest}
  \end{itemize}
\end{frame}

\subsection{Integration with userland graphic stacks}

\begin{frame}{KMS Userland Graphic Stacks}
  \begin{itemize}
  \item Tried Weston (standard Wayland implementation) and Qt with a KMS
        backend
  \item First thing to note: they're not ready for KMS drivers without
        OpenGL support (\code{DRIVER_RENDER} capabilities)!
    \begin{itemize}
      \item Wayland works (thanks to pixmam support) but does not support
            planes and hardware cursors when OpenGL support is disabled
      \item Qt only works with the fbdev backend
      \item WIP on the mesa stack to provide soft OpenGL when using a KMS
            driver without OpenGL support
      \item But the window composition will most likely be done through the
            soft OpenGL, which implies poor performance
    \end{itemize}
  \item Not sure you can choose a specific plane when using a window manager
        (e.g. stream video content on a plane which support YUV format)
  \end{itemize}
\end{frame}

\begin{frame}
  \begin{center}
  \Huge
  Questions?\\
  \vspace{1.5cm}
  \huge
  Boris Brezillon\\
  \large
  \vspace{0.5cm}
  \code{boris.brezillon@bootlin.com}
  \vspace{0.5cm}
  \newline Slides under CC-BY-SA 3.0\\
  \scriptsize
  \url{http://bootlin.com/pub/conferences/2014/elce/brezillon-drm-kms/}
  \end{center}
\end{frame}

\end{document}
