[U-Boot] [PATCH RFC] imx: add multi-architecture README

Tapani tapani at technexion.com
Mon Nov 11 13:03:05 CET 2013


Eric,

this documentation is a very good initiative. In overall I agree with what you 
have sketched, and it in many ways what we have demonstrated working in practice.

There are a few question marks I have around your suggestion. Mainly around how
the pinmuxing is suggested to be done.

See the comments inline.

On Sat,  9 Nov 2013 13:12:42 -0700
Eric Nelson <eric.nelson at boundarydevices.com> wrote:

> Signed-off-by: Eric Nelson <eric.nelson at boundarydevices.com>
> ---
>  doc/README.imx6-multi-arch | 254 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 254 insertions(+)
>  create mode 100644 doc/README.imx6-multi-arch
> 
> diff --git a/doc/README.imx6-multi-arch b/doc/README.imx6-multi-arch
> new file mode 100644
> index 0000000..a31718c
> --- /dev/null
> +++ b/doc/README.imx6-multi-arch
> @@ -0,0 +1,254 @@
> +Supporting multiple architectures on Freescale i.MX6
> +
> +This file describes how to support multiple CPU architectures
> +(i.MX6DQ and i.MX6DLS) in a single U-Boot image.
> +
> +Because memory configuration differs between architectures,
> +auto-configuration of DDR is also covered.
> +
> +1. BACKGROUND
> +-------------
> +The Freescale i.MX6 processor family contains four processors which are pin 
> +compatible. Refer to http://freescale.com/imx6series for details and reference 
> +manuals, but the highlights from a U-Boot perspective are as follows:
> +
> +i.MX6Q	- Quad core, 64-bit DDR1066, 256K OCRAM
> +i.MX6D	- Dual core, 64-bit DDR1066, 256K OCRAM
> +i.MX6DL	- Dual core, 64-bit DDR800, 128K OCRAM
> +i.MX6S	- Single core, 32-bit DDR800, 128K OCRAM
> +
> +These processors are also largely register-compatible, but not completely.
> +In particular, the IOMUX registers for common functions are in different
> +locations and have different selector values.
> +

Let's not assume that list supported CPUs is complete yet (and you haven't). 

> +The register addresses and values are consistent between the first
> +two processors in the list above (i.MX6DQ processors) and the second
> +two (i.MX6DLS for Dual-Lite/Solo).
> +
> +The i.MX6SL (Solo-Lite) processor is not pin compatible, so this 
> +document does not describe support for that variant.
> +
> +Because of the pin-compatibility, a number of manufacturers produce 
> +identical boards with BOM options for two or more of the processors.
> +
> +Similarly, identical boards are offered in a number of different
> +memory layouts, whether by partially populating the DRAM sockets
> +or by populating them with different densities of DDR.
> +
> +By following the conventions described in this document, a board
> +can support each of these options in a single boot image, and
> +decrease the overhead for managing images.
> +
> +Note that adding multi-arch support will add to the size of the
> +bootable image and slow the boot process slightly. If size and
> +speed are critical, a configuration-specific build can be produced
> +that removes this overhead.
> +
> +2. BOOT FLOW
> +------------
> +The boot process for i.MX6 processors begins with execution of a first 
> +level loader in the processor's internal ROM. This loader samples
> +boot pins and on-chip fuses to determine the source of the secondary
> +boot image.
> +
> +The boot image itself consists of a header (the DCD) which describes 
> +the load address and payload (the U-Boot firmware). It also contains
> +a set of register/value pairs used to initialize the CPU prior
> +to execution of U-Boot.
> +
> +The boot image is produced in a final stage of the build process
> +by the imximage tool by processing a configuration (.cfg) file.
> +
> +In a single-architecture, single memory-layout image, the DCD
> +can include DDR memory initialization values and the load address
> +may be DDR directly.
> +
> +In order to support multiple processors, the DCD must contain
> +a load address for the i.MX6's internal RAM (OCRAM) because the 
> +DDR memory speed (at least) will be dependent on the processor 
> +variant. Thankfully, the DCD items needed to load this binary
> +are consistent between all of the processors.
> +
> +For this reason, support for SPL (secondary program loader) is 
> +a requirement in order to support multiple architectures in the 
> +same image. The SPL image will determine the processor variant
> +and memory configuration, configure the IOMUX controller and
> +DDR appropriately, then load either a full version of U-Boot 
> +or an O/S.
> +
> +3. DDR configuration
> +--------------------
> +
> +The DDR configuration data for single architecture boards is defined
> +within .cfg files in the various board directories.
> +
> +As of this writing, most boards use the structure defined in 
> +board/boundary/nitrogen6x/ that separates the pieces of DCD
> +data according to function, with this general form:
> +
> +	#include "ddr-setup.cfg"
> +	#include "1066mhz_4x128mx16.cfg"
> +	#include "clocks.cfg"
> +
> +Note that only the second of these is specific to the CPU
> +variant or memory-layout, and the multi-arch equivalent
> +can simply omit that for later initialization.
> +
> +	#include "ddr-setup.cfg"
> +	#include "clocks.cfg"
> +
> +In order to support the use of the memory configuration
> +files by both the SPL code and the imximage tool, the
> +memory configuration files (1066mhz_4x128mx16.cfg, et cetera)
> +have been converted to use the DCD_REG macro.
> +
> +In other words, this declaration in 1066mhz_4x128mx16.cfg
> +
> +	DCD_REG(MX6_MMDC_P0_MDCFG0, 0x555A7974)
> +
> +will be turned into this by the preprocessor when
> +used by imximage:
> +	
> +	DATA 4, MX6_MMDC_P0_MDCFG0, 0x555A7974
> +
> +and this when used to generate memory configuration tables
> +used by the SPL:
> +	{MX6_MMDC_P0_MDCFG0, 0x555A7974},
> +
> +3. IOMUX declarations
> +---------------------
> +
> +The declarations inside the header files
> +	arch/arm/include/asm/arch-mx6/mx6q_pins.h
> +and
> +	arch/arm/include/asm/arch-mx6/mx6dl_pins.h
> +
> +are used to configure the pads usage for a particular
> +board design.
> +
> +As mentioned earlier, the register addresses and values
> +are different between the 6DQ and 6DLS processor sets,
> +and these differences are expressed in two header files:
> +

The wording is a little imprecise here :-)

Change the formulation to "can be different" (unless you know for sure
they can never bee the same, even for the upcoming imx6 models).
The header files contain the padconfigs rather than differences.

> +For i.MX6Q and i.MX6D:
> +	arch/arm/include/asm/arch-mx6/mx6q_pins.h
> +
> +and for i.MX6DL and i.MX6S:
> +	arch/arm/include/asm/arch-mx6/mx6dls_pins.h
> +
> +For example, the SD3_DAT2 pad is used for SD card data
> +on all currently supported i.MX6 boards. 
> +
> +On i.MX6DQ, this is selected by writing a zero to the
> +mux register at address 0x020E02C8. On i.MX6DLS, the
> +address is 0x020E031C.
> +
> +The header files mx6q_pins.h and mx6dls_pins consolidate
> +the settings through a macro providing a common name
> +of SD3_DAT2__USDHC3_DAT2:
> +
> +	MX6_PAD_DECL(SD3_DAT2__USDHC3_DAT2,...)
> +
> +By using the MX6_PAD_DECL macro, this can be expanded
> +in one of three ways, depending on the declarations of 
> +CONFIG_MX6x by a board file. Valid options are:
> +
> +	MX6Q	- single architecture for i.MX6DQ
> +	MX6DL	- single architecture for i.MX6DL/S
> +	MX6QDL	- multi-architecture
> +
> +In the first two cases, the MX6_PAD_DECL macro will 
> +be expanded into a declararation with the MX6_PAD_
> +prefix:
> +	MX6_PAD_name = IOMUX_PAD(...)
> +
> +In the last case, the MX6_PAD_DECL macro will be
> +expanded into two sets of declarations, with the
> +prefix MX6Q_PAD_ for the i.MX6DQ pads and the
> +prefix MX6DL_PAD_ for the i.MX6DLS pads.
> +
> +This is accomplished by the header file mx6-pins.h:
> +
> +	#ifdef CONFIG_MX6QDL
> +	enum {
> +		#define MX6_PAD_DECL ...
> +		#include "mx6q_pins.h"
> +		
> +		#define MX6_PAD_DECL ...
> +		#include "mx6dl_pins.h"
> +	};
> +	#elif defined(CONFIG_MX6Q)
> +	enum {
> +		#define MX6_PAD_DECL ...
> +		#include "mx6q_pins.h"
> +	};
> +	#elif defined(CONFIG_MX6DL)
> +	enum {
> +		#define MX6_PAD_DECL ...
> +		#include "mx6dl_pins.h"
> +	};
> +	#endif
> +

Opinion: This is a terrible macro kludge to begin with. However, I'm afraid there 
is no solutions completely free macro hacks, but maybe we can have less of them?

Technical point: Could you clarify how this approach scales? There are still 
new imx6 models to be released (imx6-next).

Short sighted thinking caused the need for this mess to begin with, just trying 
to not do the same mistake again.

I think it is better to have one set of macro definitions for DL, Q, x1, x2,...
and leave the current definitions untouched for compatibility with current boards.
The price of duplicate definitions is less than extensive macro-messing. (Opinion,
again).


> +4. IOMUX usage in board files
> +-----------------------------
> +
> +The machinery described above is sufficient to allow a set of
> +pad registers to be defined for a specific architecture:
> +
> +	static iomux_v3_cfg_t const mypads[] = {
> +		MX6_PAD_x,
> +		...
> +	};
> +
> +or multiple architectures:
> +	static iomux_v3_cfg_t const mx6q_pads[] = {
> +		MX6Q_PAD_x,
> +		...
> +	};
> +
> +	static iomux_v3_cfg_t const mx6dl_pads[] = {
> +		MX6DL_PAD_x,
> +		...
> +	};
> +
> +In practice, 90% of the references to pads are in these
> +types of static arrays, and mostly separated by usage
> +(ethernet pads in a different array from UART pads).
> +
> +Going forward, it is recommended that these be consolidated
> +instead by architecture, such that all pads that apply to
> +both i.MX6DQ and i.MX6DLS architectures are defined in 
> +"boardname-pads.h" with macros of this form:
> +	MX6_PAD_DEF(PAD_REFERENCE)
> +
> +And that this file be included twice when being used in a
> +multi-architecture build. 
> +
> +e.g.
> +	static iomux_v3_cfg_t const mx6q_nitrogen_pads[] = {
> +		#define MX6_PAD_DEF(PAD_DEF) MX6Q_PAD_#PAD_DEF,
> +		#include "nitrogen6x-pads.h"
> +	};
> +	static iomux_v3_cfg_t const mx6dl_nitrogen_pads[] = {
> +		#define MX6_PAD_DEF(PAD_DEF) MX6DL_PAD_#PAD_DEF,
> +		#include "nitrogen6x-pads.h"
> +	}};
> +
> +Doing this allows the bulk of the pads to be defined in a
> +single place.
> +

Opinion: Maybe call these files something else than header files, since
they are rather some kind of .pad files.

Also I do not like this overuse of the C preprocessor, the mess created
easily gets unreadable. Maybe it already is...? :-)
Even with this description, it is not immediately obvious how it works.

> +For pads that are specific to i.MX6DQ or i.MX6DLS, it is 
> +recommended that they be defined directly in the board file.
> +
> +Finally, the convenience macro MX6REF(x) allows run-time
> +selection of a variable based on the CPU type on which
> +the reference is made:
> +
> +	imx_iomux_v3_setup_multiple_pads(
> +		MX6REF(nitrogen_pads),
> +		ARRAY_SIZE(MX6REF(nitrogen_pads))
> +	);
> +
> +N.B. This doesn't work, since ARRAY_SIZE can't be passed this
> +kind of reference...
> +

We have suggested an alternative solution, but somehow nobody seem
to notice. We avoid almost all the preprocessor messing, and have the
definitions only once. And it would scale for even more cpu types.
Admittedly, the drawback is duplicate padconf macro definitions
(or having to convert the existing boards padconfigs).  

In my opinion (and experience) the duplicate definitions is worth it.

Regardless, how we end up doing this -- this documentation is an 
excellent initiative and discussion point.

Thanks and regards,

//Tapani



More information about the U-Boot mailing list