drm/amd/display - Display Core (DC)¶
placeholder - general description of supported platforms, what dc is, etc.
Because it is partially shared with other operating systems, the Display Core Driver is divided in two pieces.
- Display Core (DC) contains the OS-agnostic components. Things like hardware programming and resource management are handled here.
- Display Manager (DM) contains the OS-dependent components. Hooks to the amdgpu base driver and DRM are implemented here.
It doesn’t help that the entire package is frequently referred to as DC. But with the context in mind, it should be clear.
When CONFIG_DRM_AMD_DC is enabled, DC will be initialized by default for supported ASICs. To force disable, set amdgpu.dc=0 on kernel command line. Likewise, to force enable on unsupported ASICs, set amdgpu.dc=1.
To determine if DC is loaded, search dmesg for the following entry:
Display Core initialized with <version number here>
AMDgpu Display Manager¶
The AMDgpu display manager, amdgpu_dm (or even simpler, dm) sits between DRM and DC. It acts as a liaison, converting DRM requests into DC requests, and DC responses into DRM responses.
The root control structure is struct amdgpu_display_manager
.
-
struct
dm_compressor_info
¶ Buffer info used by frame buffer compression
Definition
struct dm_compressor_info {
void *cpu_addr;
struct amdgpu_bo *bo_ptr;
uint64_t gpu_addr;
};
Members
cpu_addr
- MMIO cpu addr
bo_ptr
- Pointer to the buffer object
gpu_addr
- MMIO gpu addr
-
struct
dmub_hpd_work
¶ Handle time consuming work in low priority outbox IRQ
Definition
struct dmub_hpd_work {
struct work_struct handle_hpd_work;
struct dmub_notification *dmub_notify;
struct amdgpu_device *adev;
};
Members
handle_hpd_work
- Work to be executed in a separate thread to handle hpd_low_irq
dmub_notify
- notification for callback function
adev
- amdgpu_device pointer
-
struct
vblank_control_work
¶ Work data for vblank control
Definition
struct vblank_control_work {
struct work_struct work;
struct amdgpu_display_manager *dm;
struct amdgpu_crtc *acrtc;
struct dc_stream_state *stream;
bool enable;
};
Members
work
- Kernel work data for the work event
dm
- amdgpu display manager device
acrtc
- amdgpu CRTC instance for which the event has occurred
stream
- DC stream for which the event has occurred
enable
- true if enabling vblank
-
struct
amdgpu_dm_backlight_caps
¶ Information about backlight
Definition
struct amdgpu_dm_backlight_caps {
union dpcd_sink_ext_caps *ext_caps;
u32 aux_min_input_signal;
u32 aux_max_input_signal;
int min_input_signal;
int max_input_signal;
bool caps_valid;
bool aux_support;
};
Members
ext_caps
- Keep the data struct with all the information about the display support for HDR.
aux_min_input_signal
- Min brightness value supported by the display
aux_max_input_signal
- Max brightness value supported by the display in nits.
min_input_signal
- minimum possible input in range 0-255.
max_input_signal
- maximum possible input in range 0-255.
caps_valid
- true if these values are from the ACPI interface.
aux_support
- Describes if the display supports AUX backlight.
Description
Describe the backlight support for ACPI or eDP AUX.
-
struct
dal_allocation
¶ Tracks mapped FB memory for SMU communication
Definition
struct dal_allocation {
struct list_head list;
struct amdgpu_bo *bo;
void *cpu_ptr;
u64 gpu_addr;
};
Members
list
- list of dal allocations
bo
- GPU buffer object
cpu_ptr
- CPU virtual address of the GPU buffer object
gpu_addr
- GPU virtual address of the GPU buffer object
-
struct
hpd_rx_irq_offload_work_queue
¶ Work queue to handle hpd_rx_irq offload work
Definition
struct hpd_rx_irq_offload_work_queue {
struct workqueue_struct *wq;
spinlock_t offload_lock;
bool is_handling_link_loss;
struct amdgpu_dm_connector *aconnector;
};
Members
wq
- workqueue structure to queue offload work.
offload_lock
- To protect fields of offload work queue.
is_handling_link_loss
- Used to prevent inserting link loss event when we’re handling link loss
aconnector
- The aconnector that this work queue is attached to
-
struct
hpd_rx_irq_offload_work
¶ hpd_rx_irq offload work structure
Definition
struct hpd_rx_irq_offload_work {
struct work_struct work;
union hpd_irq_data data;
struct hpd_rx_irq_offload_work_queue *offload_wq;
};
Members
work
- offload work
data
- reference irq data which is used while handling offload work
offload_wq
- offload work queue that this work is queued to
-
struct
amdgpu_display_manager
¶ Central amdgpu display manager device
Definition
struct amdgpu_display_manager {
struct dc *dc;
struct dmub_srv *dmub_srv;
struct dmub_notification *dmub_notify;
dmub_notify_interrupt_callback_t dmub_callback[AMDGPU_DMUB_NOTIFICATION_MAX];
bool dmub_thread_offload[AMDGPU_DMUB_NOTIFICATION_MAX];
struct dmub_srv_fb_info *dmub_fb_info;
const struct firmware *dmub_fw;
struct amdgpu_bo *dmub_bo;
u64 dmub_bo_gpu_addr;
void *dmub_bo_cpu_addr;
uint32_t dmcub_fw_version;
struct cgs_device *cgs_device;
struct amdgpu_device *adev;
struct drm_device *ddev;
u16 display_indexes_num;
struct drm_private_obj atomic_obj;
struct mutex dc_lock;
struct mutex audio_lock;
#if defined(CONFIG_DRM_AMD_DC_DCN);
spinlock_t vblank_lock;
#endif;
struct drm_audio_component *audio_component;
bool audio_registered;
struct list_head irq_handler_list_low_tab[DAL_IRQ_SOURCES_NUMBER];
struct list_head irq_handler_list_high_tab[DAL_IRQ_SOURCES_NUMBER];
struct common_irq_params pflip_params[DC_IRQ_SOURCE_PFLIP_LAST - DC_IRQ_SOURCE_PFLIP_FIRST + 1];
struct common_irq_params vblank_params[DC_IRQ_SOURCE_VBLANK6 - DC_IRQ_SOURCE_VBLANK1 + 1];
struct common_irq_params vline0_params[DC_IRQ_SOURCE_DC6_VLINE0 - DC_IRQ_SOURCE_DC1_VLINE0 + 1];
struct common_irq_params vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
struct common_irq_params dmub_trace_params[1];
struct common_irq_params dmub_outbox_params[1];
spinlock_t irq_handler_list_table_lock;
struct backlight_device *backlight_dev[AMDGPU_DM_MAX_NUM_EDP];
const struct dc_link *backlight_link[AMDGPU_DM_MAX_NUM_EDP];
uint8_t num_of_edps;
struct amdgpu_dm_backlight_caps backlight_caps[AMDGPU_DM_MAX_NUM_EDP];
struct mod_freesync *freesync_module;
#ifdef CONFIG_DRM_AMD_DC_HDCP;
struct hdcp_workqueue *hdcp_workqueue;
#endif;
#if defined(CONFIG_DRM_AMD_DC_DCN);
struct workqueue_struct *vblank_control_workqueue;
#endif;
struct drm_atomic_state *cached_state;
struct dc_state *cached_dc_state;
struct dm_compressor_info compressor;
const struct firmware *fw_dmcu;
uint32_t dmcu_fw_version;
const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box;
#if defined(CONFIG_DRM_AMD_DC_DCN);
uint32_t active_vblank_irq_count;
#endif;
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY);
struct crc_rd_work *crc_rd_wrk;
#endif;
struct hpd_rx_irq_offload_work_queue *hpd_rx_offload_wq;
struct amdgpu_encoder mst_encoders[AMDGPU_DM_MAX_CRTC];
bool force_timing_sync;
bool disable_hpd_irq;
bool dmcub_trace_event_en;
struct list_head da_list;
struct completion dmub_aux_transfer_done;
struct workqueue_struct *delayed_hpd_wq;
u32 brightness[AMDGPU_DM_MAX_NUM_EDP];
};
Members
dc
- Display Core control structure
dmub_srv
- DMUB service, used for controlling the DMUB on hardware that supports it. The pointer to the dmub_srv will be NULL on hardware that does not support it.
dmub_notify
- Notification from DMUB.
dmub_callback
- Callback functions to handle notification from DMUB.
dmub_thread_offload
- Flag to indicate if callback is offload.
dmub_fb_info
- Framebuffer regions for the DMUB.
dmub_fw
- DMUB firmware, required on hardware that has DMUB support.
dmub_bo
- Buffer object for the DMUB.
dmub_bo_gpu_addr
- GPU virtual address for the DMUB buffer object.
dmub_bo_cpu_addr
- CPU address for the DMUB buffer object.
dmcub_fw_version
- DMCUB firmware version.
cgs_device
- The Common Graphics Services device. It provides an interface for accessing registers.
adev
- AMDGPU base driver structure
ddev
- DRM base driver structure
display_indexes_num
- Max number of display streams supported
atomic_obj
- In combination with
dm_atomic_state
it helps manage global atomic state that doesn’t map cleanly into existing drm resources, likedc_context
. dc_lock
- Guards access to DC functions that can issue register write sequences.
audio_lock
- Guards access to audio instance changes.
vblank_lock
- Guards access to deferred vblank work state.
audio_component
- Used to notify ELD changes to sound driver.
audio_registered
- True if the audio component has been registered successfully, false otherwise.
irq_handler_list_low_tab
Low priority IRQ handler table.
It is a n*m table consisting of n IRQ sources, and m handlers per IRQ source. Low priority IRQ handlers are deferred to a workqueue to be processed. Hence, they can sleep.
Note that handlers are called in the same order as they were registered (FIFO).
irq_handler_list_high_tab
High priority IRQ handler table.
It is a n*m table, same as
irq_handler_list_low_tab
. However, handlers in this table are not deferred and are called immediately.pflip_params
- Page flip IRQ parameters, passed to registered handlers when triggered.
vblank_params
- Vertical blanking IRQ parameters, passed to registered handlers when triggered.
vline0_params
- OTG vertical interrupt0 IRQ parameters, passed to registered handlers when triggered.
vupdate_params
- Vertical update IRQ parameters, passed to registered handlers when triggered.
dmub_trace_params
- DMUB trace event IRQ parameters, passed to registered handlers when triggered.
irq_handler_list_table_lock
- Synchronizes access to IRQ tables
backlight_dev
- Backlight control device
backlight_link
- Link on which to control backlight
backlight_caps
- Capabilities of the backlight device
freesync_module
- Module handling freesync calculations
hdcp_workqueue
- AMDGPU content protection queue
vblank_control_workqueue
- Deferred work for vblank control events.
cached_state
- Caches device atomic state for suspend/resume
cached_dc_state
- Cached state of content streams
compressor
- Frame buffer compression buffer. See
struct dm_compressor_info
fw_dmcu
- Reference to DMCU firmware
dmcu_fw_version
- Version of the DMCU firmware
soc_bounding_box
- gpu_info FW provided soc bounding box struct or 0 if not available in FW
active_vblank_irq_count
- number of currently active vblank irqs
crc_rd_wrk
- Work to be executed in a separate thread to communicate with PSP.
hpd_rx_offload_wq
- Work queue to offload works of hpd_rx_irq
mst_encoders
- fake encoders used for DP MST.
force_timing_sync
- set via debugfs. When set, indicates that all connected displays will be forced to synchronize.
dmcub_trace_event_en
- enable dmcub trace events
da_list
- DAL fb memory allocation list, for communication with SMU.
brightness
- cached backlight values.
Lifecycle¶
DM (and consequently DC) is registered in the amdgpu base driver as a IP block. When CONFIG_DRM_AMD_DC is enabled, the DM device IP block is added to the base driver’s device list to be initialized and torn down accordingly.
The functions to do so are provided as hooks in struct amd_ip_funcs
.
-
int
dm_hw_init
(void *handle)¶ Initialize DC device
Parameters
void *handle
- The base driver device containing the amdgpu_dm device.
Description
Initialize the struct amdgpu_display_manager
device. This involves calling
the initializers of each DM component, then populating the struct with them.
Although the function implies hardware initialization, both hardware and software are initialized here. Splitting them out to their relevant init hooks is a future TODO item.
Some notable things that are initialized here:
- Display Core, both software and hardware
- DC modules that we need (freesync and color management)
- DRM software states
- Interrupt sources and handlers
- Vblank support
- Debug FS entries, if enabled
-
int
dm_hw_fini
(void *handle)¶ Teardown DC device
Parameters
void *handle
- The base driver device containing the amdgpu_dm device.
Description
Teardown components within struct amdgpu_display_manager
that require
cleanup. This involves cleaning up the DRM device, DC, and any modules that
were loaded. Also flush IRQ workqueues and disable them.
Interrupts¶
DM provides another layer of IRQ management on top of what the base driver already provides. This is something that could be cleaned up, and is a future TODO item.
The base driver provides IRQ source registration with DRM, handler
registration into the base driver’s IRQ table, and a handler callback
amdgpu_irq_handler()
, with which DRM calls on interrupts. This generic
handler looks up the IRQ table, and calls the respective
amdgpu_irq_src_funcs.process
hookups.
What DM provides on top are two IRQ tables specifically for top-half and bottom-half IRQ handling, with the bottom-half implementing workqueues:
They override the base driver’s IRQ table, and the effect can be seen
in the hooks that DM provides for amdgpu_irq_src_funcs.process
. They
are all set to the DM generic handler amdgpu_dm_irq_handler()
, which looks up
DM’s IRQ tables. However, in order for base driver to recognize this hook, DM
still needs to register the IRQ with the base driver. See
dce110_register_irq_handlers() and dcn10_register_irq_handlers().
To expose DC’s hardware interrupt toggle to the base driver, DM implements
amdgpu_irq_src_funcs.set
hooks. Base driver calls it through
amdgpu_irq_update()
to enable or disable the interrupt.
-
struct
amdgpu_dm_irq_handler_data
¶ Data for DM interrupt handlers.
Definition
struct amdgpu_dm_irq_handler_data {
struct list_head list;
interrupt_handler handler;
void *handler_arg;
struct amdgpu_display_manager *dm;
enum dc_irq_source irq_source;
struct work_struct work;
};
Members
list
- Linked list entry referencing the next/previous handler
handler
- Handler function
handler_arg
- Argument passed to the handler when triggered
dm
- DM which this handler belongs to
irq_source
- DC interrupt source that this handler is registered for
work
- work struct
-
void
dm_irq_work_func
(struct work_struct *work)¶ Handle an IRQ outside of the interrupt handler proper.
Parameters
struct work_struct *work
- work struct
-
void
unregister_all_irq_handlers
(struct amdgpu_device *adev)¶ Cleans up handlers from the DM IRQ table
Parameters
struct amdgpu_device *adev
- The base driver device containing the DM device
Description
Go through low and high context IRQ tables and deallocate handlers.
-
void *
amdgpu_dm_irq_register_interrupt
(struct amdgpu_device *adev, struct dc_interrupt_params *int_params, void (*ih)(void *), void *handler_args)¶ Register a handler within DM.
Parameters
struct amdgpu_device *adev
- The base driver device containing the DM device.
struct dc_interrupt_params *int_params
- Interrupt parameters containing the source, and handler context
void (*ih)(void *)
- Function pointer to the interrupt handler to register
void *handler_args
- Arguments passed to the handler when the interrupt occurs
Description
Register an interrupt handler for the given IRQ source, under the given context. The context can either be high or low. High context handlers are executed directly within ISR context, while low context is executed within a workqueue, thereby allowing operations that sleep.
Registered handlers are called in a FIFO manner, i.e. the most recently registered handler will be called first.
Return
- Handler data
struct amdgpu_dm_irq_handler_data
containing the IRQ - source, handler function, and args
-
void
amdgpu_dm_irq_unregister_interrupt
(struct amdgpu_device *adev, enum dc_irq_source irq_source, void *ih)¶ Remove a handler from the DM IRQ table
Parameters
struct amdgpu_device *adev
- The base driver device containing the DM device
enum dc_irq_source irq_source
- IRQ source to remove the given handler from
void *ih
- Function pointer to the interrupt handler to unregister
Description
Go through both low and high context IRQ tables, and find the given handler for the given irq source. If found, remove it. Otherwise, do nothing.
-
int
amdgpu_dm_irq_init
(struct amdgpu_device *adev)¶ Initialize DM IRQ management
Parameters
struct amdgpu_device *adev
- The base driver device containing the DM device
Description
Initialize DM’s high and low context IRQ tables.
The N by M table contains N IRQ sources, with M
struct amdgpu_dm_irq_handler_data
hooked together in a linked list. The
list_heads are initialized here. When an interrupt n is triggered, all m
handlers are called in sequence, FIFO according to registration order.
The low context table requires special steps to initialize, since handlers
will be deferred to a workqueue. See struct irq_list_head
.
-
void
amdgpu_dm_irq_fini
(struct amdgpu_device *adev)¶ Tear down DM IRQ management
Parameters
struct amdgpu_device *adev
- The base driver device containing the DM device
Description
Flush all work within the low context IRQ table.
-
int
amdgpu_dm_irq_handler
(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry)¶ Generic DM IRQ handler
Parameters
struct amdgpu_device *adev
- amdgpu base driver device containing the DM device
struct amdgpu_irq_src *source
- Unused
struct amdgpu_iv_entry *entry
- Data about the triggered interrupt
Description
Calls all registered high irq work immediately, and schedules work for low irq. The DM IRQ table is used to find the corresponding handlers.
-
void
amdgpu_dm_hpd_init
(struct amdgpu_device *adev)¶ hpd setup callback.
Parameters
struct amdgpu_device *adev
- amdgpu_device pointer
Description
Setup the hpd pins used by the card (evergreen+). Enable the pin, set the polarity, and enable the hpd interrupts.
-
void
amdgpu_dm_hpd_fini
(struct amdgpu_device *adev)¶ hpd tear down callback.
Parameters
struct amdgpu_device *adev
- amdgpu_device pointer
Description
Tear down the hpd pins used by the card (evergreen+). Disable the hpd interrupts.
-
void
dm_pflip_high_irq
(void *interrupt_params)¶ Handle pageflip interrupt
Parameters
void *interrupt_params
- ignored
Description
Handles the pageflip interrupt by notifying all interested parties that the pageflip has been completed.
-
void
dm_crtc_high_irq
(void *interrupt_params)¶ Handles CRTC interrupt
Parameters
void *interrupt_params
- used for determining the CRTC instance
Description
Handles the CRTC/VSYNC interrupt by notfying DRM’s VBLANK event handler.
Atomic Implementation¶
WIP
-
void
amdgpu_dm_atomic_commit_tail
(struct drm_atomic_state *state)¶ AMDgpu DM’s commit tail implementation.
Parameters
struct drm_atomic_state *state
- The atomic state to commit
Description
This will tell DC to commit the constructed DC state from atomic_check, programming the hardware. Any failures here implies a hardware failure, since atomic check should have filtered anything non-kosher.
-
int
amdgpu_dm_atomic_check
(struct drm_device *dev, struct drm_atomic_state *state)¶ Atomic check implementation for AMDgpu DM.
Parameters
struct drm_device *dev
- The DRM device
struct drm_atomic_state *state
- The atomic state to commit
Description
Validate that the given atomic state is programmable by DC into hardware.
This involves constructing a struct dc_state
reflecting the new hardware
state we wish to commit, then querying DC to see if it is programmable. It’s
important not to modify the existing DC state. Otherwise, atomic_check
may unexpectedly commit hardware changes.
When validating the DC state, it’s important that the right locks are acquired. For full updates case which removes/adds/updates streams on one CRTC while flipping on another CRTC, acquiring global lock will guarantee that any such full update commit will wait for completion of any outstanding flip using DRMs synchronization events.
Note that DM adds the affected connectors for all CRTCs in state, when that might not seem necessary. This is because DC stream creation requires the DC sink, which is tied to the DRM connector state. Cleaning this up should be possible but non-trivial - a possible TODO item.
Return
-Error code if validation failed.
Display Core¶
WIP
FreeSync Video¶
When a userspace application wants to play a video, the content follows a standard format definition that usually specifies the FPS for that format. The below list illustrates some video format and the expected FPS, respectively:
- TV/NTSC (23.976 FPS)
- Cinema (24 FPS)
- TV/PAL (25 FPS)
- TV/NTSC (29.97 FPS)
- TV/NTSC (30 FPS)
- Cinema HFR (48 FPS)
- TV/PAL (50 FPS)
- Commonly used (60 FPS)
- Multiples of 24 (48,72,96 FPS)
The list of standards video format is not huge and can be added to the connector modeset list beforehand. With that, userspace can leverage FreeSync to extends the front porch in order to attain the target refresh rate. Such a switch will happen seamlessly, without screen blanking or reprogramming of the output in any other way. If the userspace requests a modesetting change compatible with FreeSync modes that only differ in the refresh rate, DC will skip the full update and avoid blink during the transition. For example, the video player can change the modesetting from 60Hz to 30Hz for playing TV/NTSC content when it goes full screen without causing any display blink. This same concept can be applied to a mode setting change.