Mode Setting Helper Functions

Helper Functions
CRTC Helper Operations
Encoder Helper Operations
Connector Helper Operations
Modeset Helper Functions Reference
fbdev Helper Functions Reference
Display Port Helper Functions Reference
EDID Helper Functions Reference
Rectangle Utilities Reference
Flip-work Helper Reference
VMA Offset Manager

The 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.

The DRM core contains one mid-layer implementation. The mid-layer provides implementations of several 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 drm_crtc_helper_set_config function can be used to fill the struct drm_crtc_funcs set_config field. When called, it will split the set_config operation in smaller, simpler operations and call the driver to handle them.

To use the mid-layer, drivers call drm_crtc_helper_add, drm_encoder_helper_add and drm_connector_helper_add functions to install their mid-layer bottom operations handlers, and fill the drm_crtc_funcs, drm_encoder_funcs and drm_connector_funcs 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.

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.

Helper Functions

  • int drm_crtc_helper_set_config(struct drm_mode_set *set);

    The drm_crtc_helper_set_config helper function is a CRTC set_config implementation. It first tries to locate the best encoder for each connector by calling the connector best_encoder helper operation.

    After locating the appropriate encoders, the helper function will call the mode_fixup 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.

    If the adjusted mode is identical to the current mode but changes to the frame buffer need to be applied, the drm_crtc_helper_set_config function will call the CRTC mode_set_base helper operation. If the adjusted mode differs from the current mode, or if the mode_set_base helper operation is not provided, the helper function performs a full mode set sequence by calling the prepare, mode_set and commit CRTC and encoder helper operations, in that order.

  • void drm_helper_connector_dpms(struct drm_connector *connector, int mode);

    The drm_helper_connector_dpms helper function is a connector dpms implementation that tracks power state of connectors. To use the function, drivers must provide dpms helper operations for CRTCs and encoders to apply the DPMS state to the device.

    The mid-layer doesn't track the power state of CRTCs and encoders. The dpms helper operations can thus be called with a mode identical to the currently active mode.

  • int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
                                                uint32_t maxX, uint32_t maxY);

    The drm_helper_probe_single_connector_modes helper function is a connector fill_modes implementation that updates the connection status for the connector and then retrieves a list of modes by calling the connector get_modes helper operation.

    The function filters out modes larger than max_width and max_height if specified. It then calls the connector mode_valid helper operation for each mode in the probed list to check whether the mode is valid for the connector.

CRTC Helper Operations

  • bool (*mode_fixup)(struct drm_crtc *crtc,
                           const struct drm_display_mode *mode,
                           struct drm_display_mode *adjusted_mode);

    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.

    The mode_fixup 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).

  • int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
                         struct drm_framebuffer *old_fb)

    Move the CRTC on the current frame buffer (stored in crtc->fb) to position (x,y). Any of the frame buffer, x position or y position may have been modified.

    This helper operation is optional. If not provided, the drm_crtc_helper_set_config function will fall back to the mode_set helper operation.

    Note

    FIXME: Why are x and y passed as arguments, as they can be accessed through crtc->x and crtc->y?

  • void (*prepare)(struct drm_crtc *crtc);

    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.

  • 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);

    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 commit operation, or programmed to the hardware immediately.

    The mode_set operation returns 0 on success or a negative error code if an error occurs.

  • void (*commit)(struct drm_crtc *crtc);

    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.

Encoder Helper Operations

  • bool (*mode_fixup)(struct drm_encoder *encoder,
                           const struct drm_display_mode *mode,
                           struct drm_display_mode *adjusted_mode);

    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 mode_fixup CRTC helper operation for an explanation of the allowed adjustments.

  • void (*prepare)(struct drm_encoder *encoder);

    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.

  • void (*mode_set)(struct drm_encoder *encoder,
                     struct drm_display_mode *mode,
                     struct drm_display_mode *adjusted_mode);

    Set a new mode. Depending on the device requirements, the mode can be stored internally by the driver and applied in the commit operation, or programmed to the hardware immediately.

  • void (*commit)(struct drm_encoder *encoder);

    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.

Connector Helper Operations

  • struct drm_encoder *(*best_encoder)(struct drm_connector *connector);

    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.

  • int (*get_modes)(struct drm_connector *connector);

    Fill the connector's probed_modes list by parsing EDID data with drm_add_edid_modes or calling drm_mode_probed_add directly for every supported mode and return the number of modes it has detected. This operation is mandatory.

    When adding modes manually the driver creates each mode with a call to drm_mode_create and must fill the following fields.

    • __u32 type;

      Mode type bitmask, a combination of

      DRM_MODE_TYPE_BUILTIN

      not used?

      DRM_MODE_TYPE_CLOCK_C

      not used?

      DRM_MODE_TYPE_CRTC_C

      not used?

      DRM_MODE_TYPE_PREFERRED - The preferred mode for the connector

      not used?

      DRM_MODE_TYPE_DEFAULT

      not used?

      DRM_MODE_TYPE_USERDEF

      not used?

      DRM_MODE_TYPE_DRIVER

      The mode has been created by the driver (as opposed to to user-created modes).

      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.

    • __u32 clock;

      Pixel clock frequency in kHz unit

    • __u16 hdisplay, hsync_start, hsync_end, htotal;
          __u16 vdisplay, vsync_start, vsync_end, vtotal;

      Horizontal and vertical timing information

                   Active                 Front           Sync           Back
                   Region                 Porch                          Porch
          <-----------------------><----------------><-------------><-------------->
      
            //////////////////////|
           ////////////////////// |
          //////////////////////  |..................               ................
                                                     _______________
      
          <----- [hv]display ----->
          <------------- [hv]sync_start ------------>
          <--------------------- [hv]sync_end --------------------->
          <-------------------------------- [hv]total ----------------------------->
      
    • __u16 hskew;
          __u16 vscan;

      Unknown

    • __u32 flags;

      Mode flags, a combination of

      DRM_MODE_FLAG_PHSYNC

      Horizontal sync is active high

      DRM_MODE_FLAG_NHSYNC

      Horizontal sync is active low

      DRM_MODE_FLAG_PVSYNC

      Vertical sync is active high

      DRM_MODE_FLAG_NVSYNC

      Vertical sync is active low

      DRM_MODE_FLAG_INTERLACE

      Mode is interlaced

      DRM_MODE_FLAG_DBLSCAN

      Mode uses doublescan

      DRM_MODE_FLAG_CSYNC

      Mode uses composite sync

      DRM_MODE_FLAG_PCSYNC

      Composite sync is active high

      DRM_MODE_FLAG_NCSYNC

      Composite sync is active low

      DRM_MODE_FLAG_HSKEW

      hskew provided (not used?)

      DRM_MODE_FLAG_BCAST

      not used?

      DRM_MODE_FLAG_PIXMUX

      not used?

      DRM_MODE_FLAG_DBLCLK

      not used?

      DRM_MODE_FLAG_CLKDIV2

      ?

      Note that modes marked with the INTERLACE or DBLSCAN flags will be filtered out by drm_helper_probe_single_connector_modes if the connector's interlace_allowed or doublescan_allowed field is set to 0.

    • char name[DRM_DISPLAY_MODE_LEN];

      Mode name. The driver must call drm_mode_set_name to fill the mode name from hdisplay, vdisplay and interlace flag after filling the corresponding fields.

    The vrefresh value is computed by drm_helper_probe_single_connector_modes.

    When parsing EDID data, drm_add_edid_modes fill the connector display_info width_mm and height_mm fields. When creating modes manually the get_modes helper operation must set the display_info width_mm and height_mm fields if they haven't been set already (for instance at initilization time when a fixed-size panel is attached to the connector). The mode width_mm and height_mm fields are only used internally during EDID parsing and should not be set when creating modes manually.

  • int (*mode_valid)(struct drm_connector *connector,
    		  struct drm_display_mode *mode);

    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 mandatory.

    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.

    Note

    Note that the mode_valid helper operation is only called for modes detected by the device, and not for modes set by the user through the CRTC set_config operation.

Modeset Helper Functions Reference

drm_helper_move_panel_connectors_to_head — move panels to the front in the connector list
drm_helper_probe_single_connector_modes — get complete set of display modes
drm_helper_encoder_in_use — check if a given encoder is in use
drm_helper_crtc_in_use — check if a given CRTC is in a mode_config
drm_helper_disable_unused_functions — disable unused objects
drm_crtc_helper_set_mode — internal helper to set a mode
drm_crtc_helper_set_config — set a new config from userspace
drm_helper_connector_dpms — connector dpms helper implementation

fbdev Helper Functions Reference

drm_fb_helper_single_add_all_connectors — add all connectors to fbdev emulation helper
drm_fb_helper_debug_enter — implementation for ->fb_debug_enter
drm_fb_helper_debug_leave — implementation for ->fb_debug_leave
drm_fb_helper_restore_fbdev_mode — restore fbdev configuration
drm_fb_helper_blank — implementation for ->fb_blank
drm_fb_helper_init — initialize a drm_fb_helper structure
drm_fb_helper_setcmap — implementation for ->fb_setcmap
drm_fb_helper_check_var — implementation for ->fb_check_var
drm_fb_helper_set_par — implementation for ->fb_set_par
drm_fb_helper_pan_display — implementation for ->fb_pan_display
drm_fb_helper_fill_fix — initializes fixed fbdev information
drm_fb_helper_fill_var — initalizes variable fbdev information
drm_fb_helper_initial_config — setup a sane initial connector configuration
drm_fb_helper_hotplug_event — respond to a hotplug notification by probing all the outputs attached to the fb
struct drm_fb_helper_funcs — driver callbacks for the fbdev emulation library

The fb helper functions are useful to provide an fbdev on top of a drm kernel mode setting driver. They can be used mostly independantely from the crtc helper functions used by many drivers to implement the kernel mode setting interfaces.

Initialization is done as a three-step process with drm_fb_helper_init, drm_fb_helper_single_add_all_connectors and drm_fb_helper_initial_config. Drivers with fancier requirements than the default beheviour can override the second step with their own code. Teardown is done with drm_fb_helper_fini.

At runtime drivers should restore the fbdev console by calling drm_fb_helper_restore_fbdev_mode from their ->lastclose callback. They should also notify the fb helper code from updates to the output configuration by calling drm_fb_helper_hotplug_event. For easier integration with the output polling code in drm_crtc_helper.c the modeset code proves a ->output_poll_changed callback.

All other functions exported by the fb helper library can be used to implement the fbdev driver interface by the driver.

Display Port Helper Functions Reference

struct i2c_algo_dp_aux_data — driver interface structure for i2c over dp aux algorithm
i2c_dp_aux_add_bus — register an i2c adapter using the aux ch helper

These functions contain some common logic and helpers at various abstraction levels to deal with Display Port sink devices and related things like DP aux channel transfers, EDID reading over DP aux channels, decoding certain DPCD blocks, ...

EDID Helper Functions Reference

drm_edid_is_valid — sanity check EDID data
drm_probe_ddc
drm_get_edid — get EDID data, if available
drm_edid_duplicate — duplicate an EDID and the extensions
drm_match_cea_mode — look for a CEA mode matching given mode
drm_edid_to_eld — build ELD from EDID
drm_edid_to_sad — extracts SADs from EDID
drm_edid_to_speaker_allocation — extracts Speaker Allocation Data Blocks from EDID
drm_av_sync_delay — HDMI/DP sink audio-video sync delay in millisecond
drm_select_eld — select one ELD from multiple HDMI/DP sinks
drm_detect_hdmi_monitor — detect whether monitor is hdmi.
drm_detect_monitor_audio — check monitor audio capability
drm_rgb_quant_range_selectable — is RGB quantization range selectable?
drm_add_edid_modes — add modes from EDID data, if available
drm_add_modes_noedid — add modes for the connectors without EDID
drm_hdmi_avi_infoframe_from_display_mode — fill an HDMI AVI infoframe with data from a DRM display mode
drm_hdmi_vendor_infoframe_from_display_mode — fill an HDMI infoframe with data from a DRM display mode

Rectangle Utilities Reference

struct drm_rect — two dimensional rectangle
drm_rect_adjust_size — adjust the size of the rectangle
drm_rect_translate — translate the rectangle
drm_rect_downscale — downscale a rectangle
drm_rect_width — determine the rectangle width
drm_rect_height — determine the rectangle height
drm_rect_visible — determine if the the rectangle is visible
drm_rect_equals — determine if two rectangles are equal
drm_rect_intersect — intersect two rectangles
drm_rect_clip_scaled — perform a scaled clip operation
drm_rect_calc_hscale — calculate the horizontal scaling factor
drm_rect_calc_vscale — calculate the vertical scaling factor
drm_rect_calc_hscale_relaxed — calculate the horizontal scaling factor
drm_rect_calc_vscale_relaxed — calculate the vertical scaling factor
drm_rect_debug_print — print the rectangle information

Utility functions to help manage rectangular areas for clipping, scaling, etc. calculations.

Flip-work Helper Reference

struct drm_flip_work — flip work queue
drm_flip_work_queue — queue work
drm_flip_work_commit — commit queued work
drm_flip_work_init — initialize flip-work
drm_flip_work_cleanup — cleans up flip-work

Util to queue up work to run from work-queue context after flip/vblank. Typically this can be used to defer unref of framebuffer's, cursor bo's, etc until after vblank. The APIs are all safe (and lockless) for up to one producer and once consumer at a time. The single-consumer aspect is ensured by committing the queued work to a single work-queue.

VMA Offset Manager

drm_vma_offset_manager_init — Initialize new offset-manager
drm_vma_offset_manager_destroy — Destroy offset manager
drm_vma_offset_lookup — Find node in offset space
drm_vma_offset_lookup_locked — Find node in offset space
drm_vma_offset_add — Add offset node to manager
drm_vma_offset_remove — Remove offset node from manager
drm_vma_node_allow — Add open-file to list of allowed users
drm_vma_node_revoke — Remove open-file from list of allowed users
drm_vma_node_is_allowed — Check whether an open-file is granted access
drm_vma_offset_exact_lookup — Look up node by exact address
drm_vma_offset_lock_lookup — Lock lookup for extended private use
drm_vma_offset_unlock_lookup — Unlock lookup for extended private use
drm_vma_node_reset — Initialize or reset node object
drm_vma_node_start — Return start address for page-based addressing
drm_vma_node_size — Return size (page-based)
drm_vma_node_has_offset — Check whether node is added to offset manager
drm_vma_node_offset_addr — Return sanitized offset for user-space mmaps
drm_vma_node_unmap — Unmap offset node
drm_vma_node_verify_access — Access verification helper for TTM

The vma-manager is responsible to map arbitrary driver-dependent memory regions into the linear user address-space. It provides offsets to the caller which can then be used on the address_space of the drm-device. It takes care to not overlap regions, size them appropriately and to not confuse mm-core by inconsistent fake vm_pgoff fields. Drivers shouldn't use this for object placement in VMEM. This manager should only be used to manage mappings into linear user-space VMs.

We use drm_mm as backend to manage object allocations. But it is highly optimized for alloc/free calls, not lookups. Hence, we use an rb-tree to speed up offset lookups.

You must not use multiple offset managers on a single address_space. Otherwise, mm-core will be unable to tear down memory mappings as the VM will no longer be linear. Please use VM_NONLINEAR in that case and implement your own offset managers.

This offset manager works on page-based addresses. That is, every argument and return code (with the exception of drm_vma_node_offset_addr) is given in number of pages, not number of bytes. That means, object sizes and offsets must always be page-aligned (as usual). If you want to get a valid byte-based user-space address for a given offset, please see drm_vma_node_offset_addr.

Additionally to offset management, the vma offset manager also handles access management. For every open-file context that is allowed to access a given node, you must call drm_vma_node_allow. Otherwise, an mmap call on this open-file with the offset of the node will fail with -EACCES. To revoke access again, use drm_vma_node_revoke. However, the caller is responsible for destroying already existing mappings, if required.