![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
RT-Thread graphic DM (components/drivers/include/drivers/graphic.h, components/drivers/graphic/graphic.c) wraps display controllers as **struct rt_graphic_device**: multi-**plane** framebuffers, EDID, optional backlight, Linux-style fb ioctls, and legacy **rt_device_graphic_ops** via **rt_graphic_device_switch_primary**.
App-facing pixel formats and **RTGRAPHIC_CTRL_*** live in **drivers/classes/graphic.h**. DM types, planes, and registration APIs are in **graphic.h**.
Implementation split:
| File | Role |
|---|---|
**graphic.c** | Device register, control, planes, EDID parse, auto-update timer, OFW backlight |
**graphic_simple.c** | Synthetic EDID + **rt_graphic_device_simple_register** |
**graphic_primary.c** | **rt_graphic_device_switch_primary** → set_pixel / draw_hline on primary FB |
**framebuffer/fb-simple.c** | DT **simple-framebuffer** — Simple framebuffer (simple-framebuffer) |
| Option | Role |
|---|---|
**RT_USING_DM** | Required parent |
**RT_USING_GRAPHIC** | Core graphic stack (graphic.c, graphic_primary.c, graphic_simple.c) |
**RT_GRAPHIC_FB** | Framebuffer drivers (e.g. **simple-framebuffer**) |
**RT_GRAPHIC_BACKLIGHT** | Backlight class + PWM/GPIO — Backlight devices |
**RT_GRAPHIC_LOGO** | Boot logo render on register — Boot Logo |
| Layer | Responsibility |
|---|---|
**rt_graphic_plane_ops** | Hardware: allocate FB, push pixels to display (**update**), teardown (**fb_cleanup**) |
**rt_graphic_device_ops** | Device-wide: DPMS, vsync, brightness, vendor **control** |
**graphic.c** | Standard **rt_device** API, rect update, mode set, hotplug, periodic flush timer |
| Field | Meaning |
|---|---|
**type** | **PRIMARY** (one), **CURSOR** (one), **OVERLAY** (list) |
**mode / modes[]** | **RTGRAPHIC_PIXEL_FORMAT_*** from classes/graphic.h |
**framebuffer**, **line_length**, **screen_len**, **framebuffer_len** | CPU-visible buffer; may be multi-buffer if **framebuffer_len > screen_len** |
**ops** | Driver callbacks (see below) |
| Callback | When called | Contract |
|---|---|---|
**fb_remap** | Mode or resolution change | Allocate/map FB for **mode** + **rect**; set **plane->framebuffer** |
**fb_cleanup** | Before remap / del_plane | Release HW resources (unmap, unref GPU resource) |
**update** | **RTGRAPHIC_CTRL_RECT_UPDATE** or auto timer | Push **rect** region to display; **width/height == 0** may mean “position only” (cursor) |
**fb_pan_display** | **RTGRAPHIC_CTRL_PAN_DISPLAY** / open | Point scanout at offset inside **framebuffer** |
**prop_set** | Optional | Z-order, rotate, alpha (**enum rt_graphic_plane_prop**) |
| Callback | Role |
|---|---|
**dpms_switch** | **RT_GRAPHIC_DPMS_*** — often ties to **rt_graphic_device_update_auto** period |
**wait_vsync** | **RTGRAPHIC_CTRL_WAIT_VSYNC** |
**set_brightness / get_brightness** | Panel brightness; may defer to **gdev->backlight** |
**get_status** | Optional connector status |
**current_plane** | Override plane used for **GET_INFO** / updates (default: primary) |
**control** | Vendor-specific commands (optional 3D / acceleration path) |
**struct edid** in **graphic.h** mirrors VESA EDID layout. **RTGRAPHIC_CTRL_GET_EXT** copies **gdev->edid**. On register, if primary plane has no size, **graphic_edid_res()** picks mode from detailed timings.
**rt_graphic_device_simple_edid(gdev, w, h, refresh_hz)** (graphic_simple.c) builds a minimal EDID when hardware has no DDC (fixed panels, simple bring-up).
| API | Role |
|---|---|
**rt_graphic_device_alloc_plane(gdev, priv_size, ops, modes, modes_nr, type)** | Allocate plane; **priv[0]** tail for driver data |
**rt_graphic_device_add_plane(gdev, plane)** | Attach primary/cursor/overlay; assigns **plane_ida** id |
**rt_graphic_device_register(gdev)** | Requires **primary_plane**; names device **fbu** via **RT_DM_IDA**; maps FB from EDID if size zero |
**rt_graphic_device_unregister(gdev)** | DPMS off, stop timer, del all planes, **rt_device_unregister** |
**rt_graphic_device_simple_register(...)** | Alloc primary plane + synthetic EDID + register (no full EDID path) |
**rt_graphic_device_simple_unregister(gdev)** | Alias for **unregister** |
Naming: **RT_DM_IDA_INIT(GRAPHIC_FRAMEBUFFER)** → devices **fb0**, **fb1**, …
OFW backlight: during **register**, **graphic_ofw_init** resolves **backlight** phandle on **dev->ofw_node** and opens the backlight device.
From **classes/graphic.h** (handled in **graphic.c** **_graphic_control**):
| Command | Behavior |
|---|---|
**RTGRAPHIC_CTRL_RECT_UPDATE** | **plane->ops->update(plane, rect)** on current plane |
**RTGRAPHIC_CTRL_SET_MODE** | **fb_remap** if mode is in **plane->modes[]** |
**RTGRAPHIC_CTRL_GET_INFO** | Fills **rt_device_graphic_info** from current plane |
**RTGRAPHIC_CTRL_POWERON / POWEROFF** | DPMS + optional backlight power |
**RTGRAPHIC_CTRL_PAN_DISPLAY** | Offset within framebuffer (double-buffer) |
**RTGRAPHIC_CTRL_WAIT_VSYNC** | Driver **wait_vsync** |
**RT_DEVICE_CTRL_CURSOR_*** | Cursor plane position / bitmap |
**FBIOGET_VSCREENINFO / FBIOPUT_VSCREENINFO** | Linux fb var screeninfo (when enabled) |
Auto flush: **rt_graphic_device_update_auto(gdev, ms)** starts a periodic timer (default idea: RT_GRAPHIC_UPDATE_MS = 16) that calls **update** on primary, overlays, and cursor. **rt_graphic_device_enter / leave** stop/restart the timer around modeset (hotplug).
Hotplug: **rt_graphic_device_hotplug_event(gdev)** re-parses EDID size, **fb_remap** primary, then fires **event_notify**.
primary_gdev** and returns **rt_device_graphic_ops** matching primary plane bpp (8/16/24/32/64).graphic.h**: **rt_graphix_ops(dev)** calls **switch_primary** then reads **dev->user_data**.set_pixel** / **draw_hline** without **RTGRAPHIC_CTRL_RECT_UPDATE**.After **register**, call **switch_primary** on the head you want for **rt_graphix_ops**.
**simple-framebuffer**: maps fixed **reg** RAM, implements plane ops as CPU memcpy — see Simple framebuffer (simple-framebuffer).
| Resource | Document |
|---|---|
| Pixel / link clock | Clock framework (CLK) |
| DSI/DP PHY | Generic PHY (Phye) |
| Panel backlight | Backlight devices (backlight DT property) |
| Coherent FB / cache | Hardware cache (hwcache), DMA engine |
Bring-up order: regulator → clock → panel init → **register** → backlight **POWERON** → **RTGRAPHIC_CTRL_POWERON**.
rt_graphic_plane_ops** (at minimum **fb_remap**, **update**, **fb_cleanup**).add_plane PRIMARY** before **register**; cursor/overlay after if needed.edid** or use **simple_register** / **simple_edid**.register** → **switch_primary** for legacy drawing APIs.remove**: **unregister** (frees planes); release clocks/reset/regulator in reverse order.hotplug_event** after EDID/mode change under **enter/leave**.update with auto timer off: apps must **RTGRAPHIC_CTRL_RECT_UPDATE** after CPU writes or nothing reaches the panel.fb_remap** — bogus EDID causes probe failure.add_plane** returns **-RT_EINVAL**.update** if scanout is non-coherent — Hardware cache (hwcache).switch_primary global**: only one **primary_gdev** — multi-head apps should use **rt_device_find("fb1")** + graphic ctrl, not **rt_graphix_ops** alone.rt_graphic_device_update_auto(gdev, 0)** or **enter** during suspend.simple-framebuffer) — **simple-framebuffer**components/drivers/include/drivers/graphic.hcomponents/drivers/include/drivers/classes/graphic.hcomponents/drivers/graphic/graphic.c, graphic_simple.c, graphic_primary.crt_dm_dev_iomap, namingRT_PLATFORM_DRIVER_EXPORT