[U-Boot] [PATCH] Add support for TechNexion edm1-cf-imx6 SoM

Tapani Utriainen tapani at technexion.com
Fri Aug 30 07:07:54 CEST 2013


Stefano,

Thank you for reviewing this patch, and for the constructive comments. 
Most of your comments are taken on board, and we will re-submit updated patches 
in the near future.

On some things we probably need some clarification, see inlined responses
to some of your questions.

> > ---
> >  MAINTAINERS                                     |   4 +
> >  arch/arm/include/asm/arch-mx6/spl.h             |  19 +
> >  board/technexion/edm_cf_imx6/Makefile           |  26 +
> >  board/technexion/edm_cf_imx6/README             |  30 +
> >  board/technexion/edm_cf_imx6/clocks.cfg         |  44 ++
> >  board/technexion/edm_cf_imx6/edm_cf_imx6.c      | 801 ++++++++++++++++++++++++
> >  board/technexion/edm_cf_imx6/edm_cf_imx6_pins.h |  44 ++
> >  board/technexion/edm_cf_imx6/imximage.cfg       |  17 +
> >  boards.cfg                                      |   1 +
> >  include/configs/edm_cf_imx6.h                   | 140 +++++
> >  10 files changed, 1126 insertions(+)
> >  create mode 100644 arch/arm/include/asm/arch-mx6/spl.h
> >  create mode 100644 board/technexion/edm_cf_imx6/Makefile
> >  create mode 100644 board/technexion/edm_cf_imx6/README
> >  create mode 100644 board/technexion/edm_cf_imx6/clocks.cfg
> >  create mode 100644 board/technexion/edm_cf_imx6/edm_cf_imx6.c
> >  create mode 100644 board/technexion/edm_cf_imx6/edm_cf_imx6_pins.h
> >  create mode 100644 board/technexion/edm_cf_imx6/imximage.cfg
> >  create mode 100644 include/configs/edm_cf_imx6.h
> > 
> 
> The patch should be split into separate patches, and each of them fixes
> a specific issue. From our previous discussion, we agree about:
> 
> - we need to clean up conflicts in pad definitions - see Eric's answer.
> - we need a way to simply defines pins for the different SOC variations.
> Eric and Troy have already proposed a schema adding tables *only* into
> the board file, and the generation of the table is quite automatic.
> Let's say, if I am a board maintainer and I want to add support for a
> board having all iMX6 variations, I would like to define only once which
> pins I need, without replicating for each SOC variant.
> - the same should be done with DDR and clocks, if necessary.
> 
> After these preparation patches, there should be a patch preparing i.MX6
> for SPL - changes in i.MX6 common code should go here.
> 
> Last, there will be a patch on top of the rest adding support to your board.
>

Understand. However, as far as I can tell Troy's suggestion is still
creating the pad setup compile time for one cpu. 
Is there something obvious we are missing?
 
> 
> Please change all license text according to the new rule with
> SPDX-License-Identifier.
>
Will do.
 
> 
> Maybe you should add some comments explaining that this is your
> decision, not due to the SOC. Only the first dd is mandatory by iMX
> (offset is 0x400 in flash). For u-boot, you have decided to put it into
> raw data exactly after SPL and not into a filesystem.
> 
> > +
> > +Only raw mmc boot has been verified to work.
> 
> The phrase is misleading, and let me think the other ways do not work. I
> assume that you tested only raw mmc, so please rephrase to explain this.
>
Not using a filesystem is by choice. We'll clarify on that 
(or maybe better, enable FAT)

...

> > +
> > +static inline void setup_boot_device(void)
> > +{
> > +	uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4);
> > +	uint bt_mem_ctl = (soc_sbmr & 0x000000FF) >> 4 ;
> > +	uint bt_mem_type = (soc_sbmr & 0x00000008) >> 3;
> > +	uint bt_mem_mmc = (soc_sbmr & 0x00001000) >> 12;
> > +
> > +	switch (bt_mem_ctl) {
> > +	case 0x0:
> > +		if (bt_mem_type)
> > +			boot_dev = ONE_NAND_BOOT;
> > +		else
> > +			boot_dev = WEIM_NOR_BOOT;
> > +		break;
> > +	case 0x2:
> > +			boot_dev = SATA_BOOT;
> > +		break;
> > +	case 0x3:
> > +		if (bt_mem_type)
> > +			boot_dev = I2C_BOOT;
> > +		else
> > +			boot_dev = SPI_NOR_BOOT;
> > +		break;
> > +	case 0x4:
> > +	case 0x5:
> > +		if (bt_mem_mmc)
> > +			boot_dev = SD0_BOOT;
> > +		else
> > +			boot_dev = SD1_BOOT;
> > +		break;
> > +	case 0x6:
> > +	case 0x7:
> > +		boot_dev = MMC_BOOT;
> > +		break;
> > +	case 0x8 ... 0xf:
> > +		boot_dev = NAND_BOOT;
> > +		break;
> > +	default:
> > +		boot_dev = UNKNOWN_BOOT;
> > +		break;
> > +	}
> > +}
> > 
> 
> Let's say: boot device is not board dependent, and the required SPL
> function should be moved into general code (imx_common or
> arch/arm/cpu/armv7/mx6).
> 

Will do. In the first patch attempt we deliberately tried not to touch
common imx6 code.

> +
> > +int dram_init(void)
> > +{
> > +	uint cpurev, imxtype;
> > +	u32 sdram_size;
> > +
> > +	cpurev = get_cpu_rev();
> > +	imxtype = (cpurev & 0xFF000) >> 12;
> 
> I am expecting to have a global function getting the cputype, with
> macros of the type is_cpu_mx6q() (I see you use it later) to help us the
> usage. Not here in board code.
> 

Added.

> > +static iomux_v3_cfg_t const edmdl_uart1_pads[] = {
> > +	MX6DL_PAD_CSI0_DAT10__UART1_TXD | MUX_PAD_CTRL(UART_PAD_CTRL),
> > +	MX6DL_PAD_CSI0_DAT11__UART1_RXD | MUX_PAD_CTRL(UART_PAD_CTRL),
> > +};
> > +
> > +static iomux_v3_cfg_t const edmq_uart1_pads[] = {
> > +	MX6Q_PAD_CSI0_DAT10__UART1_TXD | MUX_PAD_CTRL(UART_PAD_CTRL),
> > +	MX6Q_PAD_CSI0_DAT11__UART1_RXD | MUX_PAD_CTRL(UART_PAD_CTRL),
> > +};
> > +
> > +static iomux_v3_cfg_t const edmdl_usdhc1_pads[] = {
> > +	MX6DL_PAD_SD1_CLK__USDHC1_CLK   | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6DL_PAD_SD1_CMD__USDHC1_CMD   | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6DL_PAD_SD1_DAT0__USDHC1_DAT0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6DL_PAD_SD1_DAT1__USDHC1_DAT1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6DL_PAD_SD1_DAT2__USDHC1_DAT2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6DL_PAD_SD1_DAT3__USDHC1_DAT3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	/* Card detect */
> > +	MX6DL_PAD_GPIO_2__GPIO_1_2      | MUX_PAD_CTRL(NO_PAD_CTRL),
> > +};
> > +
> > +static iomux_v3_cfg_t const edmq_usdhc1_pads[] = {
> > +	MX6Q_PAD_SD1_CLK__USDHC1_CLK   | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6Q_PAD_SD1_CMD__USDHC1_CMD   | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6Q_PAD_SD1_DAT0__USDHC1_DAT0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6Q_PAD_SD1_DAT1__USDHC1_DAT1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6Q_PAD_SD1_DAT2__USDHC1_DAT2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	MX6Q_PAD_SD1_DAT3__USDHC1_DAT3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
> > +	/* Card detect */
> > +	MX6Q_PAD_GPIO_2__GPIO_1_2      | MUX_PAD_CTRL(NO_PAD_CTRL),
> > +};
> 
> I do not like this solution: this is a bare duplication of the pads, and
> it is prone to errors. The definitions of the table must be in some way
> automatic. I want to define a pin: if SD1_CLK is used for MMC, this does
> not depend from the SOC variant.
>

TBH, I hate this solution as well. But guess we heard Eric's cries for mercy, 
and did it the way Boundary (and several kernel board files) do it -- rather 
than the way we did it in the Wandboard kernel.

> What about Troy's solution ?
> 
Did not apply? And still had a mess of arrays in the board file. Or what we
have *is* the multi-cpu variant of Troy's approach...?
(With both CPU type macros expanded, manually)

> 
> Let's say : this does not scale well. For each peripheral we have
> exactly the same code. The if..then..else should be hidden in some way,
> using macros to select the right table.
> 
...
> 
> As you see, we can have a lot of some code.
> 
...
> 
> Again here.
>
Beating a dead horse. I happily killed that mess in the WB kernel once already.

> > +
> > +int board_early_init_f(void)
> > +{
> > +	setup_iomux_uart();
> > +	return 0;
> > +}
> > +
> > +/*
> > + * Do not overwrite the console
> > + * Use always serial for U-Boot console
> > + */
> > +int overwrite_console(void)
> > +{
> > +	return 1;
> > +}
> 
> I have not seen CONFIG_VIDEO in your configuration file. Is this dead code ?
>
Yes, we cut away the splash screen support from the submitted patch.
(Our original patch was against another u-boot version, and we tried to cut out 
everything non-essential or thoroughly tested).

Will cut even more :-)
 
> > +#if defined(CONFIG_SPL_BUILD)
> > +void board_init_f(ulong dummy)
> > +{
> > +	/* Set the stack pointer. */
> > +	asm volatile("mov sp, %0\n" : : "r"(CONFIG_SPL_STACK));
> > +
> > +	/* Clear the BSS. */
> > +	memset(__bss_start, 0, __bss_end - __bss_start);
> > +
> > +	/* Set global data pointer. */
> > +	gd = &gdata;
> > +
> > +	arch_cpu_init();
> > +	board_early_init_f();
> > +	timer_init();
> > +	preloader_console_init();
> > +
> > +	board_init_r(NULL, 0);
> > +}
> 
> None of this stuff is board specific - we need to factorize this, making
> available for all i.MX6 boards. I will say, for i.MX5, too.
>
Will try.
 
> > +
> > +static void spl_dram_init_mx6solo_512mb(void)
> > +{
> > +	/* DDR3 initialization based on the MX6Solo Auto Reference Design (ARD) */
> > +	/* DDR IO TYPE */
> > +	writel(0x000c0000, IOMUXC_BASE_ADDR + 0x774);
> > +	writel(0x00000000, IOMUXC_BASE_ADDR + 0x754);
> > +	/* Clock */
> > +	writel(0x00000030, IOMUXC_BASE_ADDR + 0x4ac);
> > +	writel(0x00000030, IOMUXC_BASE_ADDR + 0x4b0);
> > +	/* Address */

[ .... long list of writels ... ]

> > +	writel(0x04008032, MMDC_P0_BASE_ADDR + 0x01c);
> > +	writel(0x00008033, MMDC_P0_BASE_ADDR + 0x01c);
> > +	writel(0x00048031, MMDC_P0_BASE_ADDR + 0x01c);
> > +	writel(0x07208030, MMDC_P0_BASE_ADDR + 0x01c);
> > +	writel(0x04008040, MMDC_P0_BASE_ADDR + 0x01c);
> > +	writel(0x00005800, MMDC_P0_BASE_ADDR + 0x020);
> > +	writel(0x00011117, MMDC_P0_BASE_ADDR + 0x818);
> > +	writel(0x00011117, MMDC_P1_BASE_ADDR + 0x818);
> > +	writel(0x0002556d, MMDC_P0_BASE_ADDR + 0x004);
> > +	writel(0x00011006, MMDC_P1_BASE_ADDR + 0x004);
> > +	writel(0x00000000, MMDC_P0_BASE_ADDR + 0x01c);
> > +}
> 
> Really I do not like this solution. First, you should accessor to set
> the iomux, without using base address + offset. And of course, access to
> the ram controller should be done in the same way using a C structure,
> not offsets.
> 
> Then the problem is similar to the pads. I will propose we have a
> general function, and the values of board specific parameters (32
> against 64 bit size, calibration registers, and so on), and start the
> ddr procedure. The functions here do the same on different registers.
> 

We agree that the does does not look pretty. But there needs to be some 
clarification. 

However, using this has some benefits:
* It is easier to convert from (and compare to) DCD tables 
* Easier to look things up in the TRM (base + offset are easier to find
in a long list of registers sorted by offset, than a name)
* It is a lot of effort to do struct accessors for huge tables. Both
of IOMUX and MMDC are large (offsets of 0x800+). Having struct
accessors would take quite long to enter manually (two tables of 500+ entries 
each, and different between cpu types). This would be hours, if not a day of
braindead work without any tangible benefit.

I could make those tables of { offset, value } and do the writels using
a for-loop, but that would just mariginally improve on the ugliness.

> > +u32 spl_boot_device(void)
> > +{
> > +	puts("Boot Device: ");
> > +	switch (get_boot_device()) {
> > +	case SD0_BOOT:
> > +		printf("SD0\n");
> > +		return BOOT_DEVICE_MMC1;
> > +	case SD1_BOOT:
> > +		printf("SD1\n");
> > +		return BOOT_DEVICE_MMC2;
> > +	case MMC_BOOT:
> > +		printf("MMC\n");
> > +		return BOOT_DEVICE_MMC2;
> > +	case NAND_BOOT:
> > +		printf("NAND\n");
> > +		return BOOT_DEVICE_NAND;
> > +	case UNKNOWN_BOOT:
> > +	default:
> > +		printf("UNKNOWN\n");
> > +		return BOOT_DEVICE_NONE;
> > +	}
> > +}
> 
> This is also common code.
> 
Yes.

> > +
> > +u32 spl_boot_mode(void)
> > +{
> > +	switch (spl_boot_device()) {
> > +	case BOOT_DEVICE_MMC1:
> > +	case BOOT_DEVICE_MMC2:
> > +	case BOOT_DEVICE_MMC2_2:
> > +#ifdef CONFIG_SPL_FAT_SUPPORT
> > +		return MMCSD_MODE_FAT;
> > +#else
> > +		return MMCSD_MODE_RAW;
> > +#endif
> > +		break;
> > +        case BOOT_DEVICE_NAND:
> > +	default:
> > +		puts("spl: ERROR:  unsupported device\n");
> > +		hang();
> > +	}
> > +}
> > +
> > +void reset_cpu(ulong addr)
> > +{
> > +
> > +}
> 
> reset_cpu for imx should activate the watchdog, see
> drivers/watchdog/imx_watchdog.c
>
Ok.
 
> > diff --git a/boards.cfg b/boards.cfg
> > index 79d6cd8..b7d66ff 100644
> > --- a/boards.cfg
> > +++ b/boards.cfg
> > @@ -288,6 +288,7 @@ nitrogen6s1g                 arm         armv7       nitrogen6x          boundar
> >  wandboard_dl		     arm	 armv7	     wandboard		 -		mx6 wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024
> >  wandboard_quad		     arm	 armv7	     wandboard		 -		mx6 wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q2g.cfg,MX6Q,DDR_MB=2048
> >  wandboard_solo		     arm	 armv7	     wandboard		 -		mx6 wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6s.cfg,MX6S,DDR_MB=512
> > +edm_cf_imx6                  arm         armv7       edm_cf_imx6         technexion     mx6 edm_cf_imx6:IMX_CONFIG=board/technexion/edm_cf_imx6/imximage.cfg,SPL
> 
> Why CONFIG_SPL is not set into the configuration file ? Is there a
> version without SPL ?
> 
There used to be... yes, we'll fix that.

> Please maintain the list sorted.
>
No problem.

... 
> > +
> > +#define MACH_TYPE_EDM_CF_IMX6		4257
> > +#define CONFIG_MACH_TYPE		MACH_TYPE_EDM_CF_IMX6
> 
> if MACH_TYPE_EDM_CF_IMX6 is used only here, better:
> 
> #define CONFIG_MACH_TYPE		4257
>
Yes, guess we tried to mimic wandboard.
 
> > +
> > +#define CONFIG_CMDLINE_TAG
> > +#define CONFIG_SETUP_MEMORY_TAGS
> > +#define CONFIG_REVISION_TAG
> > +

> 
> > +#ifdef CONFIG_SPL
> > +#define CONFIG_SPL_FRAMEWORK
> > +#define CONFIG_SPL_TEXT_BASE          0x00908400
> 
> Ok - SPL goes into IRAM, that is good. Can you explain me the value of
> the 0x8400 offset ?
> 
The available IRAM starts at 907000 and we need space for the IVT tables.

> > +#define CONFIG_SPL_PAD_TO 0x400
> > +#define CONFIG_SPL_START_S_PATH     "arch/arm/cpu/armv7"
> > +#define CONFIG_SPL_STACK	0x0091FFB8
> 
> Maybe better set it with some size - where is coming this value ?
> 

From page 393 in the imx6solo TRM. That is Freescale's recommended initial 
stack top.

regards,

//Tapani


More information about the U-Boot mailing list