[RFCv2] doc: develop: Describe system configuration

Pali Rohár pali at kernel.org
Thu Jul 28 21:05:07 CEST 2022

On Thursday 28 July 2022 14:53:49 Tom Rini wrote:
> Start by describing in general the best practices for how to implement
> configuration of some aspect of U-Boot.  This generally means finding
> the right choices for when something should be static or dynamically
> configured and enabled.  Then further document when to use CONFIG or CFG
> namespaces for static configuration.
> Signed-off-by: Tom Rini <trini at konsulko.com>
> ---
> RFCv2:
> - Based on Pali's feedback, remove the README section and start a new
>   section in this document to cover when to use each namespace. Try and
>   be clear about when to use "hidden" Kconfig options rather than CFG as
>   well.
> - Based on Heinrich's feedback, rename this to system_configuration.rst
>   and include some introductory remarks on when to use some dynamic or
>   static configuration.  Link to the driver model code for dynamic
>   configuration and then explain the CONFIG vs CFG namespaces for static
>   configuration.
> RFCv1:
> - This is essentially my idea on how to better handle the problem of
>   CONFIG values that just don't fit in Kconfig because it makes much
>   more sense to define them statically for a given SoC or calculate them
>   from other values, and so on.  One example here would be to revert
>   c7fad78ec0ee ("Convert CONFIG_SYS_BR0_PRELIM et al to Kconfig") and
>   re-name these to CFG_SYS_.. instead. Another big example here would be
>   a global search-and-replace of 's/CONFIG_HPS_/CFG_HPS_/g' as that's
>   all tool-generated. Not all CONFIG_SYS_ options would get this as
>   boolean choices are well handled in Kconfig, and that may not be clear
>   enough in what I wrote here?
> ---
>  README                               |  21 -----
>  doc/develop/index.rst                |   1 +
>  doc/develop/system_configuration.rst | 121 +++++++++++++++++++++++++++
>  3 files changed, 122 insertions(+), 21 deletions(-)
>  create mode 100644 doc/develop/system_configuration.rst
> diff --git a/README b/README
> index 2c4bde0b3297..623f35907217 100644
> --- a/README
> +++ b/README
> @@ -166,27 +166,6 @@ Directory Hierarchy:
>  Software Configuration:
>  =======================
> -Configuration is usually done using C preprocessor defines; the
> -rationale behind that is to avoid dead code whenever possible.
> -
> -There are two classes of configuration variables:
> -
> -* Configuration _OPTIONS_:
> -  These are selectable by the user and have names beginning with
> -  "CONFIG_".
> -
> -* Configuration _SETTINGS_:
> -  These depend on the hardware etc. and should not be meddled with if
> -  you don't know what you're doing; they have names beginning with
> -  "CONFIG_SYS_".
> -
> -Previously, all configuration was done by hand, which involved creating
> -symbolic links and editing configuration files manually. More recently,
> -U-Boot has added the Kbuild infrastructure used by the Linux kernel,
> -allowing you to use the "make menuconfig" command to configure your
> -build.
> -
> -
>  Selection of Processor Architecture and Board Type:
>  ---------------------------------------------------
> diff --git a/doc/develop/index.rst b/doc/develop/index.rst
> index 73741ceb6a2f..7c41e3f1b6e5 100644
> --- a/doc/develop/index.rst
> +++ b/doc/develop/index.rst
> @@ -13,6 +13,7 @@ General
>     designprinciples
>     process
>     release_cycle
> +   system_configuration
>  Implementation
>  --------------
> diff --git a/doc/develop/system_configuration.rst b/doc/develop/system_configuration.rst
> new file mode 100644
> index 000000000000..bb09d1f974d4
> --- /dev/null
> +++ b/doc/develop/system_configuration.rst
> @@ -0,0 +1,121 @@
> +.. SPDX-License-Identifier: GPL-2.0+
> +
> +U-Boot system configuration
> +===========================
> +
> +There are a number of different aspects to configuring U-Boot to build and then
> +run on a given platform or set of platforms. Broadly speaking, some aspects of
> +the world can be configured at run time and others must be done at build time.
> +In general run time is preferred over build time. But when making these
> +decision, we also need to consider if we're talking about feature that could be
> +useful to virtually every platform or something specific to a single hardware
> +platform. The resulting image size is also another important consideration.
> +Finally, the overall requirements of being able to do run time detection will
> +have an impact on if it's possible or not.
> +
> +When adding new features to U-Boot, be they a new subsystem or SoC support or
> +new platform for an existing supported SoC, the preferred configuration order
> +is:
> +
> +#. Simple run time. One example here are chip revision checks. Another is
> +   knowing that we've checked GPIOs and are on revision B of a platform, rather
> +   than doing a more expensive device tree check. This allows us to use a single
> +   device tree for revision A and B in this case and perform fixups as needed
> +   rather than storing two device trees.
> +
> +#. Making use of our Kconfig infrastructure and the ``CONFIG`` namespace. The
> +   primary method of build time configuration is done via the ``CONFIG``
> +   namespace and Kconfig infrastructure. This is generally the best fit for when
> +   we want to enable or disable some sort of feature, such as the SoC or network
> +   support.
> +
> +#. Making use of the :doc:`device tree <devicetree/control>` to determine at
> +   run time how to configure a feature that we have enabled via Kconfig. For
> +   example, we would use Kconfig to enable an i2c chip driver, but the device
> +   tree to know where the i2c chip resides in memory and other details we need
> +   in order to configure the bus.
> +
> +#. Making use of C header files directly and the ``CFG`` namespace. This is
> +   useful when for various reasons we cannot get configuration values that we
> +   need from the device tree so instead have them defined in a header and use
> +   the prefix ``CFG_`` in their definition.
> +
> +Dynamic run time configuration methods.
> +---------------------------------------
> +
> +For more information in general on how to make use of this please start with the
> +:doc:`driver model <driver-model/index>` documentation.
> +
> +Static build time configuration methods
> +---------------------------------------
> +
> +There are two namespaces used to control the build time configuration of
> +U-Boot, ``CONFIG`` and ``CFG``. These are used when it is either not possible
> +or not practical to make a run time determination about some functionality of
> +the hardware or a required software feature or similar. Each of these has their
> +own places where they are better suited than the other for use.
> +
> +The first of these, ``CONFIG``` is managed in the `Kconfig language
> +<https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html>`_ that is
> +most commonly associated with the Linux kernel and the Kconfig files found
> +throughout our sources. Adding options to this namespace is the preferred way of
> +exposing new configuration options as there are a number of ways for both users
> +and system integrators to manage and change these options. Some common examples
> +here are to enable a specific command within U-Boot or even a whole subsystem
> +such as NAND flash or network connectivity.
> +
> +The second of these, ``CFG`` is implemented directly as C preprocessor values or
> +macros, depending on what they are in turn describing. The nature of U-Boot
> +means that while we have some functionality that is very reasonable to expose to
> +the end user to enable or disable we have other places where we need to describe
> +things such as register locations or values, memory map ranges and so on. When
> +practical, we should be getting these values from the device tree . However,
> +there are cases where this is either not practical due to when we need the
> +information and may not have a device tree yet or due to legacy reasons code has
> +not been rewritten.
> +
> +When to use each namespace
> +^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +While there are some cases where it should be fairly obvious where to use each
> +namespace, as for example a command would be ``CONFIG`` and a header of values
> +generated by an external tool should be ``CFG`` there will be cases where it's
> +less clear and one needs to take care when implementing. In general,
> +configuration *options* should be ``CONFIG`` and configuration *settings* should
> +be ``CFG``. Since it is not always clear however, let us discuss things to
> +keep in mind when adding to either namespace.
> +
> +A thing to keep in mind is that we have a strong preference for using the
> +``CONFIG`` namespace first. Options expressed this way let us make use of the
> +Kconfig language to express dependencies and abstractions. Consider the example
> +of a SHA256 hardware acceleration engine. This would be a feature of the SoC and
> +so something to not ask the user if it exists, but we would want to have our
> +generic framework for such engines be optionally available and depend on knowing
> +we have this engine on a given hardware platform. Expressing this should be done
> +as a hidden symbol that is ``select``'ed by the SoC symbol which would in turn
> +be ``select``'ed by the board option, which is user visible. This means that
> +hardware features that are either present or not present should be in the
> +``CONFIG`` namespace and in a similar manner, features which will always have a
> +constant value such as "this SoC always has 4 cores and 4 threads per core"
> +should be as well.
> +
> +This brings us to differentiating between a configuration *setting* versus a
> +hardware feature. To build on the previous example, while we may know the number
> +of cores and threads, it's possible that within a given family of SoCs the base
> +addresses of peripherals has changed, but the register offsets within have not.
> +And for practical reasons, we cannot get this information at run time from the
> +device tree. This is a case where it is reasonable to instead make use of the
> +``CFG`` namespace and that it is pure C preprocessor macros to define that
> +``CFG_SYS_FOO_REG`` is ``(CFG_SYS_FOO_BASE + 0x200)`` and have blocks of those
> +under ``#if defined(CONFIG_SOC_FOO1) ... #elif defined(CONFIG_SOC_FOO2) ...
> +#endif`` in a system header file. Another example here is register values. Often
> +it will make the most sense to construct these from other values and then using
> +masks and shifts to turn a list of "magic values" in to something that is easier
> +for humans to parse as well.
> +
> +When it has been determined that the practical solution for where to have
> +something is in the ``CFG`` namespace, the next decision is where to place these
> +settings. It is strongly encouraged to place these in the architecture header
> +files, if they are generic to a given SoC, or under the board directory if board
> +specific. Placing them under the board.h file in the *include/configs/*
> +directory should be seen as a last resort.
> -- 
> 2.25.1

Sounds good.

The only missing bit of information for me, which I really do not know
still remain... Where, how and in which format to store board specific
CFG option which is required for architecture or SoC for proper setup?

It cannot be in board/ subdir because arch/ code cannot use it (and even
do not know which include file should use). It cannot be in arch/ subdir
because it is SoC specific (e.g. arch would have to use long spaghetti
#if defined(BOARD_1) ... #elif defined(BOARD_2) ... #endif block). And
it cannot be in include/configs/ because you do not like it and do not
want it here.

Currently this issue is _un_solved by using CONFIG option either in
Kconfig or in include/configs/ ... and both options are not ideal.

I just do not see how to solve this problem.

More information about the U-Boot mailing list