Hi Michal, hi Matt,
On 15.03.20 06:41, Matt B wrote:
You probably want to speak with Nico. He's a libgfxinit expert afaik.
thanks for the heads up :)
On Wed, Mar 11, 2020 at 9:45 AM Michal Zygowski michal.zygowski@3mdeb.com wrote:
Particularly I would like to implement Braswell support for native graphics init with libgfxinit.
Angel is also looking forward to Braswell support. He mentioned it as a possible summer-of-code stretch goal (after Bay Trail support), IIRC. But applications are not written yet (start tomorrow).
I see the programming manuals from Intel
are in place: https://01.org/linuxgraphics/documentation/hardware-specification-prms
Alas, this is a pitfall for Braswell. The only part that matters for libgfxinit (information about the display engine) is 100% scrubbed away. If you look into the `Display` chapter, it only contains legacy VGA registers and audio verbs, nothing about display at all. And if you search for any of "hdmi", "lvds", "mipi", "dsi", or "lane" in the `Register` chapter: nothing :-/
So for Braswell, the only public information source I know is the Linux driver i915. It's the one exception btw. All other chips have a proper `Display` chapter. Hence also the idea to add Bay Trail support first. Even if it turns out to be much different, we could at least tell if Brasswell is closer to Bay Trail or the newer Haswell/Apollo Lake engine.
What do I need to implement a new microarchitecture in libgfxinit? Where to start and what should I focus on?
This may get a little longer... but I knew I'll have to write it down eventually.
In Ada, the code is organized in so called `packages`. In the way they are used in libgfxinit, one can simply see them as compilation units. Each package has a specification (.ads) file with declarations and a body (.adb) with code. Much like a header and a c file. Packages form a hierarchy and the name of the file has to reflect the package name, including its parents (stupid, imho).
Libgfxinit has two major mechanisms in place to support different hardware generations:
1. Alternative implementations of packages. These are organized in sub-directories (also because every alternative package body has to have the same file name). For instance, we have different implementations for the package `HW.GFX.GMA.Connectors` in g45/, ironlake/, haswell_shared/ (the latter is shared with all newer generations since Haswell).
Having alternative implementations of packages also means we can't build one binary that supports all generations. Luckily, we don't have to, so far :)
2. Configuration flags that are tested in shared code. Much like we have `if (CONFIG(FOO_BAR))` in coreboot, we have `if Config.Foo_Bar then` in libgfxinit.
All these flags are gathered in a single package `HW.GFX.GMA.Config` which keeps conditions on specific hardware generations in a central place. The file, `hw-gfx-gma-config.ads.template`, is pre-processed with some sed-foo (see `common/Makefile.inc`). The comment from `hw-gfx-gma-config.ads.template:99` on explains some of the rea- soning.
How much code sharing makes sense depends on the similarity to other hardware generations. I wouldn't be surprised if Bay Trail and Braswell end up using the g45/ code (no PCH and probably pre DDI which was intro- duced with Haswell), but I don't know that yet.
Some more about the central packages:
HW.GFX* (excluding HW.GFX.GMA*) ===============================
There's some vendor-agnostic code around. Mostly for DP training and EDID interpretation.
HW.GFX.GMA ==========
This exposes the primary interface (procedure Update_Outputs()) and contains the overall control flow for setting up displays. Update_Outputs() takes a list of configurations for each graphics pipeline (up to three) and will try to set things up according to the configuration.
Assuming a pipe is unconfigured, roughly the following steps are performed (by procedure Enable_Output()):
* Optionally select a link configuration (e.g. for DP, how many lanes at what rate). * Allocate a PLL for the pixel/DP clock. * Try to train the selected link configuration (if there is none, the loops simply run once): - Prepare output connectors (Pre_On) - Enable the graphics pipeline (On) - Finalize the output-connector configuration (Post_On)
This usually doesn't need changes for new hardware.
HW.GFX.GMA.Pipe_Setup* (formerly Display_Controller) ====================================================
At the heart of the display engine is the pipe setup. Here we configure the framebuffer format (how to interpret bytes from DRAM), image pro- cessing (e.g. scaling) and the `Transcoders` that turn the image into a continuous stream of bits (including blank times) for a given pixel clock. IOW, everything from the framebuffer to a modeline.
This was called `Display_Controller` earlier (probably for historical Linux reasons) and is still inside `hw-gfx-gma.adb` (easy to fix, but I didn't care to so far).
It's mostly configured by flags from the `Config` package. Configu- ration of scalers is often implemented very differently, but most of it didn't change much over the years.
HW.GFX.GMA.Connectors =====================
The `Connectors` package dispatches the Pre_On() and Post_On() calls (before and after configuring the graphics pipeline) to sub-packages for the individual connector types.
This is a bit subtle. In a sense, `Connectors` reflect the outputs of the CPU package. In the first generations with a PCH (Ironlake including Sandy and Ivy Bridge) the CPU didn't have actual display outputs (like VGA, LVDS, HDMI etc.) but only links to the PCH which contained the final outputs. Later, the final outputs went back onto the CPU die. So we have three very different versions of this package:
* g45/ outputs are in the GMCH (or CPU if one would add Bay Trail, it shouldn't matter). * ironlake/ FDI links in the CPU and (most) outputs in the PCH. * haswell_shared/ newer outputs (DDI) in the CPU (no legacy interfaces like VGA/LVDS, and HDMI/DP configuration changed since g45/).
If none of these match the hardware to be added, one would have to write a new one.
HW.GFX.GMA.PLLs ===============
Usually there are some similarities but often changes between hardware generations.
HW.GFX.GMA.Power_And_Clocks ===========================
This started with some setup for generation specific things that didn't find another place. Newer generations have configurable clocks and can turn individual parts of the display engine on and off. Older ones often just have to report a pre-set Core Display Clock (CDClk).
To wrap it up, `Power_And_Clocks` and `PLLs` most often need changes for new hardware. Followed by `Connectors` if these changed significantly, but most often one can add some code controlled by `Config` flags here. And, not to forget, all flags in the `Config` package need to be checked how they should be set for the new hardware.
tl;dr; Haven't written anything in SPARK/Ada yet. It will be a new adventure for me.
Can be fun but can also be exhausting ;) Depends much on how you can cope with nagging compilers and related tools.
Nico