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.
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
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.
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 optional connector
mode_valid
helper operation for each mode in
the probed list to check whether the mode is valid for the connector.
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.
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.
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.
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
not used?
not used?
not used?
not used?
not used?
not used?
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
Horizontal sync is active high
Horizontal sync is active low
Vertical sync is active high
Vertical sync is active low
Mode is interlaced
Mode uses doublescan
Mode uses composite sync
Composite sync is active high
Composite sync is active low
hskew provided (not used?)
not used?
not used?
not used?
?
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 initialization 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 optional.
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 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.
current
task an output poll worker?
This library provides some helper code for output probing. It provides an implementation of the core connector->fill_modes interface with drm_helper_probe_single_connector_modes.
It also provides support for polling connectors with a work item and for generic hotplug interrupt handling where the driver doesn't or cannot keep track of a per-connector hpd interrupt.
This helper library can be used independently of the modeset helper library. Drivers can also overwrite different parts e.g. use their own hotplug handling code to avoid probing unrelated outputs.
The fb helper functions are useful to provide an fbdev on top of a drm kernel mode setting driver. They can be used mostly independently 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 behaviour 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 provides 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.
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, ...
The DisplayPort AUX channel is an abstraction to allow generic, driver- independent access to AUX functionality. Drivers can take advantage of this by filling in the fields of the drm_dp_aux structure.
Transactions are described using a hardware-independent drm_dp_aux_msg
structure, which is passed into a driver's .transfer
implementation.
Both native and I2C-over-AUX transactions are supported.
Utility functions to help manage rectangular areas for clipping, scaling, etc. calculations.
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.
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.