Understanding Linux Graphics Display: DRM, Framebuffer, and Component Framework
This article explains the Linux graphics display stack, covering FBDEV, DRM/KMS, V4L2, framebuffer memory layout, CRTC, plane, encoder/connector structures, ioctl registration, the component framework for device initialization, and how to use the libdrm‑provided modetest tool.
Linux graphics display options
FBDEV – the legacy framebuffer device, now rarely used as development has shifted to DRM.
DRM/KMS – Direct Rendering Manager and Kernel Mode Setting, the mainstream method with high community activity, providing fine‑grained control and forming a standard ecosystem for graphics driver development.
V4L2 – Video for Linux 2, primarily for video capture scenarios; it lacks good support for complex graphics controllers.
DRM system composition
The kernel‑level DRM system consists of two major parts: an abstraction of graphics devices and a memory controller for the devices.
The kernel provides a standard DRM interface to user space; user‑space libraries build various graphics protocols on top of this, and applications use those middleware layers.
Framebuffer memory
A framebuffer is a memory region used to store display data. Its implementation in the kernel can be based on:
CMA helper (drivers/gpu/drm/drm_fb_cma_helper.c)
Scatter‑Gather (drivers/gpu/drm/tegra/)
IOMMU (drivers/gpu/drm/exynos/exynos_drm_iommu.c)
Frame format definitions use FOURCC codes, for example:
/* 24 bpp RGB */
#define DRM_FORMAT_RGB888 fourcc_code('R','G','2','4')
#define DRM_FORMAT_BGR888 fourcc_code('B','G','2','4')
/* 32 bpp RGB */
#define DRM_FORMAT_XRGB8888 fourcc_code('X','R','2','4')
#define DRM_FORMAT_XBGR8888 fourcc_code('X','B','2','4')
#define DRM_FORMAT_RGBX8888 fourcc_code('R','X','2','4')
#define DRM_FORMAT_BGRX8888 fourcc_code('B','X','2','4')CRTC (Cathode Ray Tube Controller)
The CRTC scans the framebuffer and generates timing signals.
static const struct drm_crtc_funcs ade_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = ade_crtc_enable_vblank,
.disable_vblank = ade_crtc_disable_vblank,
};Plane
Planes represent overlay layers that can be blended onto the CRTC output.
static const struct drm_plane_funcs ade_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};Encoder and Connector
Encoders convert CRTC timing into signals required by external devices (e.g., HDMI). Connectors represent the physical ports (HDMI, DisplayPort, DSI, etc.) and are usually bound to an encoder.
static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
.atomic_check = dsi_encoder_atomic_check,
.mode_valid = dsi_encoder_mode_valid,
.mode_set = dsi_encoder_mode_set,
.enable = dsi_encoder_enable,
.disable = dsi_encoder_disable,
};
static const struct drm_encoder_funcs dw_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};IOCTL registration
Typical ioctl registration diagrams are shown (image omitted for brevity).
Component framework
The kernel component framework ensures that subsystems initialize devices in a defined order. A "master" device registers itself with component_master_add_with_match, while ordinary components register with component_add.
static int kirin_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct component_match *match = NULL;
struct device_node *remote;
remote = of_graph_get_remote_node(np, 0, 0);
if (!remote)
return -ENODEV;
drm_of_component_match_add(dev, &match, compare_of, remote);
of_node_put(remote);
return component_master_add_with_match(dev, &kirin_drm_ops, match);
}Component devices are probed similarly, allocating driver data, parsing device tree, and finally calling component_add.
static int dsi_probe(struct platform_device *pdev)
{
struct dsi_data *data;
struct dw_dsi *dsi;
struct dsi_hw_ctx *ctx;
int ret;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
DRM_ERROR("failed to allocate dsi data.
");
return -ENOMEM;
}
dsi = &data->dsi;
ctx = &data->ctx;
dsi->ctx = ctx;
ret = dsi_parse_dt(pdev, dsi);
if (ret)
return ret;
platform_set_drvdata(pdev, data);
return component_add(&pdev->dev, &dsi_ops);
}Device tree definitions
The device tree must follow the component framework layout so that all components form a complete topology. Example snippets illustrate the ADE and DSI nodes, their registers, clocks, and port connections.
ade: ade@f4100000 {
compatible = "hisilicon,hi6220-ade";
reg = <0x0 0xf4100000 0x0 0x7800>;
reg-names = "ade_base";
hisilicon,noc-syscon = <&medianoc_ade>;
resets = <&media_ctrl MEDIA_ADE>;
interrupts = <0 115 4>;
clocks = <&media_ctrl HI6220_ADE_CORE>,
<&media_ctrl HI6220_CODEC_JPEG>,
<&media_ctrl HI6220_ADE_PIX_SRC>;
clock-names = "clk_ade_core", "clk_codec_jpeg", "clk_ade_pix";
assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
<&media_ctrl HI6220_CODEC_JPEG>;
assigned-clock-rates = <360000000>, <288000000>;
dma-coherent;
status = "disabled";
port {
ade_out: endpoint {
remote-endpoint = <&dsi_in>;
};
};
};
dsi: dsi@f4107800 {
compatible = "hisilicon,hi6220-dsi";
reg = <0x0 0xf4107800 0x0 0x100>;
clocks = <&media_ctrl HI6220_DSI_PCLK>;
clock-names = "pclk";
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dsi_in: endpoint {
remote-endpoint = <&ade_out>;
};
};
};
};modetest utility
The modetest program, provided by libdrm, can query device capabilities, perform basic display tests, and set display modes. Sample output shows how different pixel formats appear on the screen.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
