|  | ==================== | 
|  | 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. | 
|  |  |