One of the challenges to contributing to the display code is the complexity of the DC component. This commit adds a documentation page that discusses the programming model used by DCN and an overview of how the display code is organized. Cc: Leo Li <sunpeng.li@amd.com> Cc: Aurabindo Pillai <aurabindo.pillai@amd.com> Cc: Hamza Mahfooz <hamza.mahfooz@amd.com> Cc: Harry Wentland <harry.wentland@amd.com> Cc: Mario Limonciello <mario.limonciello@amd.com> Cc: Christian Konig <christian.koenig@amd.com> Cc: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
162 lines
8.9 KiB
ReStructuredText
162 lines
8.9 KiB
ReStructuredText
====================
|
||
DC Programming Model
|
||
====================
|
||
|
||
In the :ref:`Display Core Next (DCN) <dcn_overview>` and :ref:`DCN Block
|
||
<dcn_blocks>` pages, you learned about the hardware components and how they
|
||
interact with each other. On this page, the focus is shifted to the display
|
||
code architecture. Hence, it is reasonable to remind the reader that the code
|
||
in DC is shared with other OSes; for this reason, DC provides a set of
|
||
abstractions and operations to connect different APIs with the hardware
|
||
configuration. See DC as a service available for a Display Manager (amdgpu_dm)
|
||
to access and configure DCN/DCE hardware (DCE is also part of DC, but for
|
||
simplicity's sake, this documentation only examines DCN).
|
||
|
||
.. note::
|
||
For this page, we will use the term GPU to refers to dGPU and APU.
|
||
|
||
Overview
|
||
========
|
||
|
||
From the display hardware perspective, it is plausible to expect that if a
|
||
problem is well-defined, it will probably be implemented at the hardware level.
|
||
On the other hand, when there are multiple ways of achieving something without
|
||
a very well-defined scope, the solution is usually implemented as a policy at
|
||
the DC level. In other words, some policies are defined in the DC core
|
||
(resource management, power optimization, image quality, etc.), and the others
|
||
implemented in hardware are enabled via DC configuration.
|
||
|
||
In terms of hardware management, DCN has multiple instances of the same block
|
||
(e.g., HUBP, DPP, MPC, etc), and during the driver execution, it might be
|
||
necessary to use some of these instances. The core has policies in place for
|
||
handling those instances. Regarding resource management, the DC objective is
|
||
quite simple: minimize the hardware shuffle when the driver performs some
|
||
actions. When the state changes from A to B, the transition is considered
|
||
easier to maneuver if the hardware resource is still used for the same set of
|
||
driver objects. Usually, adding and removing a resource to a `pipe_ctx` (more
|
||
details below) is not a problem; however, moving a resource from one `pipe_ctx`
|
||
to another should be avoided.
|
||
|
||
Another area of influence for DC is power optimization, which has a myriad of
|
||
arrangement possibilities. In some way, just displaying an image via DCN should
|
||
be relatively straightforward; however, showing it with the best power
|
||
footprint is more desirable, but it has many associated challenges.
|
||
Unfortunately, there is no straight-forward analytic way to determine if a
|
||
configuration is the best one for the context due to the enormous variety of
|
||
variables related to this problem (e.g., many different DCN/DCE hardware
|
||
versions, different displays configurations, etc.) for this reason DC
|
||
implements a dedicated library for trying some configuration and verify if it
|
||
is possible to support it or not. This type of policy is extremely complex to
|
||
create and maintain, and amdgpu driver relies on Display Mode Library (DML) to
|
||
generate the best decisions.
|
||
|
||
In summary, DC must deal with the complexity of handling multiple scenarios and
|
||
determine policies to manage them. All of the above information is conveyed to
|
||
give the reader some idea about the complexity of driving a display from the
|
||
driver's perspective. This page hopes to allow the reader to better navigate
|
||
over the amdgpu display code.
|
||
|
||
Display Driver Architecture Overview
|
||
====================================
|
||
|
||
The diagram below provides an overview of the display driver architecture;
|
||
notice it illustrates the software layers adopted by DC:
|
||
|
||
.. kernel-figure:: dc-components.svg
|
||
|
||
The first layer of the diagram is the high-level DC API represented by the
|
||
`dc.h` file; below it are two big blocks represented by Core and Link. Next is
|
||
the hardware configuration block; the main file describing it is
|
||
the`hw_sequencer.h`, where the implementation of the callbacks can be found in
|
||
the hardware sequencer folder. Almost at the end, you can see the block level
|
||
API (`dc/inc/hw`), which represents each DCN low-level block, such as HUBP,
|
||
DPP, MPC, OPTC, etc. Notice on the left side of the diagram that we have a
|
||
different set of layers representing the interaction with the DMUB
|
||
microcontroller.
|
||
|
||
Basic Objects
|
||
-------------
|
||
|
||
The below diagram outlines the basic display objects. In particular, pay
|
||
attention to the names in the boxes since they represent a data structure in
|
||
the driver:
|
||
|
||
.. kernel-figure:: dc-arch-overview.svg
|
||
|
||
Let's start with the central block in the image, `dc`. The `dc` struct is
|
||
initialized per GPU; for example, one GPU has one `dc` instance, two GPUs have
|
||
two `dc` instances, and so forth. In other words we have one 'dc' per 'amdgpu'
|
||
instance. In some ways, this object behaves like the `Singleton` pattern.
|
||
|
||
After the `dc` block in the diagram, you can see the `dc_link` component, which
|
||
is a low-level abstraction for the connector. One interesting aspect of the
|
||
image is that connectors are not part of the DCN block; they are defined by the
|
||
platform/board and not by the SoC. The `dc_link` struct is the high-level data
|
||
container with information such as connected sinks, connection status, signal
|
||
types, etc. After `dc_link`, there is the `dc_sink`, which is the object that
|
||
represents the connected display.
|
||
|
||
.. note::
|
||
For historical reasons, we used the name `dc_link`, which gives the
|
||
wrong impression that this abstraction only deals with physical connections
|
||
that the developer can easily manipulate. However, this also covers
|
||
conections like eDP or cases where the output is connected to other devices.
|
||
|
||
There are two structs that are not represented in the diagram since they were
|
||
elaborated in the DCN overview page (check the DCN block diagram :ref:`Display
|
||
Core Next (DCN) <dcn_overview>`); still, it is worth bringing back for this
|
||
overview which is `dc_stream` and `dc_state`. The `dc_stream` stores many
|
||
properties associated with the data transmission, but most importantly, it
|
||
represents the data flow from the connector to the display. Next we have
|
||
`dc_state`, which represents the logic state within the hardware at the moment;
|
||
`dc_state` is composed of `dc_stream` and `dc_plane`. The `dc_stream` is the DC
|
||
version of `drm_crtc` and represents the post-blending pipeline.
|
||
|
||
Speaking of the `dc_plane` data structure (first part of the diagram), you can
|
||
think about it as an abstraction similar to `drm_plane` that represents the
|
||
pre-blending portion of the pipeline. This image was probably processed by GFX
|
||
and is ready to be composited under a `dc_stream`. Normally, the driver may
|
||
have one or more `dc_plane` connected to the same `dc_stream`, which defines a
|
||
composition at the DC level.
|
||
|
||
Basic Operations
|
||
----------------
|
||
|
||
Now that we have covered the basic objects, it is time to examine some of the
|
||
basic hardware/software operations. Let's start with the `dc_create()`
|
||
function, which directly works with the `dc` data struct; this function behaves
|
||
like a constructor responsible for the basic software initialization and
|
||
preparing for enabling other parts of the API. It is important to highlight
|
||
that this operation does not touch any hardware configuration; it is only a
|
||
software initialization.
|
||
|
||
Next, we have the `dc_hardware_init()`, which also relies on the `dc` data
|
||
struct. Its main function is to put the hardware in a valid state. It is worth
|
||
highlighting that the hardware might initialize in an unknown state, and it is
|
||
a requirement to put it in a valid state; this function has multiple callbacks
|
||
for the hardware-specific initialization, whereas `dc_hardware_init` does the
|
||
hardware initialization and is the first point where we touch hardware.
|
||
|
||
The `dc_get_link_at_index` is an operation that depends on the `dc_link` data
|
||
structure. This function retrieves and enumerates all the `dc_links` available
|
||
on the device; this is required since this information is not part of the SoC
|
||
definition but depends on the board configuration. As soon as the `dc_link` is
|
||
initialized, it is useful to figure out if any of them are already connected to
|
||
the display by using the `dc_link_detect()` function. After the driver figures
|
||
out if any display is connected to the device, the challenging phase starts:
|
||
configuring the monitor to show something. Nonetheless, dealing with the ideal
|
||
configuration is not a DC task since this is the Display Manager (`amdgpu_dm`)
|
||
responsibility which in turn is responsible for dealing with the atomic
|
||
commits. The only interface DC provides to the configuration phase is the
|
||
function `dc_validate_with_context` that receives the configuration information
|
||
and, based on that, validates whether the hardware can support it or not. It is
|
||
important to add that even if the display supports some specific configuration,
|
||
it does not mean the DCN hardware can support it.
|
||
|
||
After the DM and DC agree upon the configuration, the stream configuration
|
||
phase starts. This task activates one or more `dc_stream` at this phase, and in
|
||
the best-case scenario, you might be able to turn the display on with a black
|
||
screen (it does not show anything yet since it does not have any plane
|
||
associated with it). The final step would be to call the
|
||
`dc_update_planes_and_stream,` which will add or remove planes.
|
||
|