[RFCv2] doc: develop: Describe system configuration

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

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

On Thu, Jul 28, 2022 at 09:05:07PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 14:53:49 Tom Rini wrote:
[snip]
+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.
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.
I think it's fine to have things in quite literally <asm/arch/soc.h> (which we have a few of already) and then as needed #if / #elif / #endif for SoC changes. Much of this _could_ be instead pulled from device trees. But that's unlikely to happen for a number of platforms. And for the board specific cases which are not converted to come out of device tree, include/configs/board.h isn't going to be able to go away for that platform just yet.
So in a round about way, yes, I'm just punting on the problem because I suspect the "right" answer is converting to driver model in a more complete way and pulling the information from the device tree. But I accept there's not a desire on anyones part to invest that much time in a dead end platform.

On Thursday 28 July 2022 15:18:03 Tom Rini wrote:
On Thu, Jul 28, 2022 at 09:05:07PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 14:53:49 Tom Rini wrote:
[snip]
+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.
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.
I think it's fine to have things in quite literally <asm/arch/soc.h> (which we have a few of already) and then as needed #if / #elif / #endif for SoC changes. Much of this _could_ be instead pulled from device trees. But that's unlikely to happen for a number of platforms. And for the board specific cases which are not converted to come out of device tree, include/configs/board.h isn't going to be able to go away for that platform just yet.
So in a round about way, yes, I'm just punting on the problem because I suspect the "right" answer is converting to driver model in a more complete way and pulling the information from the device tree. But I accept there's not a desire on anyones part to invest that much time in a dead end platform.
-- Tom
Driver model and device tree is probably the better place. But in case such option is required for SoC setup to allow U-Boot to access device tree then it cannot be in device tree...

On Thu, Jul 28, 2022 at 09:21:52PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 15:18:03 Tom Rini wrote:
On Thu, Jul 28, 2022 at 09:05:07PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 14:53:49 Tom Rini wrote:
[snip]
+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.
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.
I think it's fine to have things in quite literally <asm/arch/soc.h> (which we have a few of already) and then as needed #if / #elif / #endif for SoC changes. Much of this _could_ be instead pulled from device trees. But that's unlikely to happen for a number of platforms. And for the board specific cases which are not converted to come out of device tree, include/configs/board.h isn't going to be able to go away for that platform just yet.
So in a round about way, yes, I'm just punting on the problem because I suspect the "right" answer is converting to driver model in a more complete way and pulling the information from the device tree. But I accept there's not a desire on anyones part to invest that much time in a dead end platform.
Driver model and device tree is probably the better place. But in case such option is required for SoC setup to allow U-Boot to access device tree then it cannot be in device tree...
I guess I need an example value or two please, that can't reside in <arch/asm/soc.h> nor can be delayed long enough to come from the device tree instead.
One thing that we can and do in some platforms do today is have SPL use a correct-enough simplified device tree so we always enable enough clocks/mux to have GPIOs work to determine the real rev we're on and pass the correct tree to full U-Boot. I don't think we have the hooks to re-evaluate the tree in full U-Boot, but perhaps we do need that.

On Thursday 28 July 2022 15:26:08 Tom Rini wrote:
On Thu, Jul 28, 2022 at 09:21:52PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 15:18:03 Tom Rini wrote:
On Thu, Jul 28, 2022 at 09:05:07PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 14:53:49 Tom Rini wrote:
[snip]
+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.
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.
I think it's fine to have things in quite literally <asm/arch/soc.h> (which we have a few of already) and then as needed #if / #elif / #endif for SoC changes. Much of this _could_ be instead pulled from device trees. But that's unlikely to happen for a number of platforms. And for the board specific cases which are not converted to come out of device tree, include/configs/board.h isn't going to be able to go away for that platform just yet.
So in a round about way, yes, I'm just punting on the problem because I suspect the "right" answer is converting to driver model in a more complete way and pulling the information from the device tree. But I accept there's not a desire on anyones part to invest that much time in a dead end platform.
Driver model and device tree is probably the better place. But in case such option is required for SoC setup to allow U-Boot to access device tree then it cannot be in device tree...
I guess I need an example value or two please, that can't reside in <arch/asm/soc.h> nor can be delayed long enough to come from the device tree instead.
For example those powerpc preliminary local bus settings which configures boot device memory mappings. Boot source is chosen by user (currently by selecting appropriate defconfig file). It is something which is board specific (based on board wiring), for each boot source different and instruct u-boot in early stage to correctly map remaining part of u-boot binary where is stored DTB blob.
I can imagine such #if / #elif / #elfi / .... block in som arch/ file with more extensions to include also sub-#if block for boot source... but well such monster #ifdef hell is unmaintainable.
Look for example how many defconfig files are there for P[12]* boards. For every one you would have to introduce #elif chain.
But this is just an example. I can imagine similar issues on other platforms which have RDB boards with tons of boot source options.
I know also ARM64 based boards which have boot strapping options to skip integrated BootROM and start booting directly from CS or other device local bus.
One thing that we can and do in some platforms do today is have SPL use a correct-enough simplified device tree so we always enable enough clocks/mux to have GPIOs work to determine the real rev we're on and pass the correct tree to full U-Boot. I don't think we have the hooks to re-evaluate the tree in full U-Boot, but perhaps we do need that.
-- Tom
We have such hooks, in proper U-Boot it is possible to do small modifications in DTB blob prior binding drivers. I'm preparing patches for Omnia board which use this feature. So it is not only possible but it is already working.
But in case device tree is not accessible yet (due to very early stage) then such hooks do not help.

On Thu, Jul 28, 2022 at 09:43:23PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 15:26:08 Tom Rini wrote:
On Thu, Jul 28, 2022 at 09:21:52PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 15:18:03 Tom Rini wrote:
On Thu, Jul 28, 2022 at 09:05:07PM +0200, Pali Rohár wrote:
On Thursday 28 July 2022 14:53:49 Tom Rini wrote:
[snip]
+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.
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.
I think it's fine to have things in quite literally <asm/arch/soc.h> (which we have a few of already) and then as needed #if / #elif / #endif for SoC changes. Much of this _could_ be instead pulled from device trees. But that's unlikely to happen for a number of platforms. And for the board specific cases which are not converted to come out of device tree, include/configs/board.h isn't going to be able to go away for that platform just yet.
So in a round about way, yes, I'm just punting on the problem because I suspect the "right" answer is converting to driver model in a more complete way and pulling the information from the device tree. But I accept there's not a desire on anyones part to invest that much time in a dead end platform.
Driver model and device tree is probably the better place. But in case such option is required for SoC setup to allow U-Boot to access device tree then it cannot be in device tree...
I guess I need an example value or two please, that can't reside in <arch/asm/soc.h> nor can be delayed long enough to come from the device tree instead.
For example those powerpc preliminary local bus settings which configures boot device memory mappings. Boot source is chosen by user (currently by selecting appropriate defconfig file). It is something which is board specific (based on board wiring), for each boot source different and instruct u-boot in early stage to correctly map remaining part of u-boot binary where is stored DTB blob.
I can imagine such #if / #elif / #elfi / .... block in som arch/ file with more extensions to include also sub-#if block for boot source... but well such monster #ifdef hell is unmaintainable.
Look for example how many defconfig files are there for P[12]* boards. For every one you would have to introduce #elif chain.
But this is just an example. I can imagine similar issues on other platforms which have RDB boards with tons of boot source options.
I know also ARM64 based boards which have boot strapping options to skip integrated BootROM and start booting directly from CS or other device local bus.
Alright. We know what the boot source is, since it's also a Kconfig option. If they're SoC specific, because we need to write in specific values to say "boot MMC #1", hex under arch/.../Kconfig that depends on SOC && BOOTMODE_FOO. If they're board specific, because it's something like "we need to set timing value 0x100 because of the lengths of the traces on the PCB", hex under board/.../Kconfig that depends on BOOTMODE_FOO.
And if it becomes a matter of "OR together these 5 different values" then maybe we just can't kill off include/config/board.h after all, and that just has to be where the board specific CFG_FOO things live.
One thing that we can and do in some platforms do today is have SPL use a correct-enough simplified device tree so we always enable enough clocks/mux to have GPIOs work to determine the real rev we're on and pass the correct tree to full U-Boot. I don't think we have the hooks to re-evaluate the tree in full U-Boot, but perhaps we do need that.
We have such hooks, in proper U-Boot it is possible to do small modifications in DTB blob prior binding drivers. I'm preparing patches for Omnia board which use this feature. So it is not only possible but it is already working.
Maybe it was some other case that was being asked about where it was wanting to re-process the whole device tree, not just modify some nodes.
But in case device tree is not accessible yet (due to very early stage) then such hooks do not help.
This should be solved either by CFG_FOO or CONFIG_FOO that's not prompted for.

On 7/28/22 20:53, 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@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
Thanks Tom for adding this helpful text on configuration. Overall we should even more move the focus from "namespace" to configuration mechanism. See below.
%s/U-Boot system/System/
We know that we are talking about U-Boot.
+===========================
+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
%s/run time/run time configuration/ %s/build time/build time configuration/
+decision, we also need to consider if we're talking about feature that could be
%s/decision/decisions/
%s/feature/a feature/
+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.
I guess you mean that run time detection is not always feasible? How about:
"Run time detection depends on the physical hardware and may not always be possible."
+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
%s/Simple run time./Run time feature detection./
- knowing that we've checked GPIOs and are on revision B of a platform, rather
Do you mean: "On some boards the revision may be detected by reading GPIOs."?
- 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
The focus on the word 'namespaces' does not provide clarity here. The choice is between:
* defining configuration variables via Kconfig * defining configuration variables via headers files
The namespace thing is secondary to this choice.
+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
%s/The nature of U-Boot means that while/While/
The removed words do not add clarity.
+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,
%s/tree ./tree./
+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 +^^^^^^^^^^^^^^^^^^^^^^^^^^
The paragraphs below are not about namespaces but about when to use Kconfig and when to use arch/Soc/board specific constants defined in headers.
+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.
Why can't we make this is a hard rule:
If it is in Kconfig it is CONFIG_. It is is not in Kconfig it is CFG_
Nothing comes to my mind where such a rule cannot be applied.
+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
The usage of namespace is irritating me here.
"We prefer to use Kconfig."
Best regards
Heinrich
+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.

On Fri, Jul 29, 2022 at 09:03:00AM +0200, Heinrich Schuchardt wrote:
On 7/28/22 20:53, 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@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
Thanks Tom for adding this helpful text on configuration. Overall we should even more move the focus from "namespace" to configuration mechanism. See below.
%s/U-Boot system/System/
We know that we are talking about U-Boot.
+===========================
+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
%s/run time/run time configuration/ %s/build time/build time configuration/
+decision, we also need to consider if we're talking about feature that could be
%s/decision/decisions/
%s/feature/a feature/
+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.
I guess you mean that run time detection is not always feasible? How about:
"Run time detection depends on the physical hardware and may not always be possible."
+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
%s/Simple run time./Run time feature detection./
- knowing that we've checked GPIOs and are on revision B of a platform, rather
Do you mean: "On some boards the revision may be detected by reading GPIOs."?
- 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
The focus on the word 'namespaces' does not provide clarity here. The choice is between:
- defining configuration variables via Kconfig
- defining configuration variables via headers files
The namespace thing is secondary to this choice.
+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
%s/The nature of U-Boot means that while/While/
The removed words do not add clarity.
+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,
%s/tree ./tree./
+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 +^^^^^^^^^^^^^^^^^^^^^^^^^^
The paragraphs below are not about namespaces but about when to use Kconfig and when to use arch/Soc/board specific constants defined in headers.
+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.
Why can't we make this is a hard rule:
If it is in Kconfig it is CONFIG_. It is is not in Kconfig it is CFG_
Nothing comes to my mind where such a rule cannot be applied.
+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
The usage of namespace is irritating me here.
"We prefer to use Kconfig."
Thanks for the feedback. I think we're overall in agreement on what I'm trying to say, just now how to say it. I'll integrate what you've said here and try and rework a few parts for v3.

On Fri, Jul 29, 2022 at 09:03:00AM +0200, Heinrich Schuchardt wrote:
On 7/28/22 20:53, 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.
[snip]
+#. Simple run time. One example here are chip revision checks. Another is
%s/Simple run time./Run time feature detection./
I'm trying to differentiate between "check this register content" or "read this EEPROM" from "parse the device tree, look for compatible strings". I'll try and reword this differently.
- knowing that we've checked GPIOs and are on revision B of a platform, rather
Do you mean: "On some boards the revision may be detected by reading GPIOs."?
I'm trying to give some useful examples, but not every example. So yes, the check GPIOs A/B/C and see what we get example.
Instead of "simple" I'm going to say hardware based, reword the section and try and not get too deep in to details.
participants (3)
-
Heinrich Schuchardt
-
Pali Rohár
-
Tom Rini