diff mbox

[U-Boot,V2,08/21] mx6: add plugin file for use with imximage.cfg

Message ID 1348281558-19520-9-git-send-email-troy.kisky@boundarydevices.com
State Changes Requested
Headers show

Commit Message

Troy Kisky Sept. 22, 2012, 2:39 a.m. UTC
The "plugin" command of mkimage can take this
file as an argument.

Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
---
 arch/arm/cpu/armv7/mx6/Makefile          |    5 +-
 arch/arm/cpu/armv7/mx6/plugin.S          |  164 ++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-mx6/imx-regs.h |    1 +
 3 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/armv7/mx6/plugin.S

Comments

Vikram Narayanan Sept. 22, 2012, 4:06 a.m. UTC | #1
On 9/22/2012 8:09 AM, Troy Kisky wrote:
> The "plugin" command of mkimage can take this
> file as an argument.

An explanation of what is "plugin" and what the file plugin.S does 
should be better. Not in the subject of the patch, you can place it as a 
README.

>
> Signed-off-by: Troy Kisky<troy.kisky@boundarydevices.com>
> ---
>   arch/arm/cpu/armv7/mx6/Makefile          |    5 +-
>   arch/arm/cpu/armv7/mx6/plugin.S          |  164 ++++++++++++++++++++++++++++++
>   arch/arm/include/asm/arch-mx6/imx-regs.h |    1 +
>   3 files changed, 169 insertions(+), 1 deletion(-)
>   create mode 100644 arch/arm/cpu/armv7/mx6/plugin.S
>
> diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile
> index cbce411..b1fce4e 100644
> --- a/arch/arm/cpu/armv7/mx6/Makefile
> +++ b/arch/arm/cpu/armv7/mx6/Makefile
> @@ -33,11 +33,14 @@ SOBJS   = lowlevel_init.o
>   SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
>   OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
>
> -all:	$(obj).depend $(LIB)
> +all:	$(obj).depend $(LIB) plugin.bin
>
>   $(LIB):	$(OBJS)
>   	$(call cmd_link_o_target, $(OBJS))
>
> +plugin.bin: plugin.o
> +	$(OBJCOPY) -O binary --gap-fill 0xff $<  $@
> +
>   #########################################################################
>
>   # defines $(obj).depend target
> diff --git a/arch/arm/cpu/armv7/mx6/plugin.S b/arch/arm/cpu/armv7/mx6/plugin.S
> new file mode 100644
> index 0000000..99c6b20
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/mx6/plugin.S
> @@ -0,0 +1,164 @@
> +/*
> + * Copyright (C) 2012 Boundary Devices Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +#include<config.h>
> +#include<asm/arch/imx-regs.h>
> +
> +#define HAB_RVT_ENTRY		0x98
> +#define HAB_RVT_FAIL_SAFE_VECT	0xbc
> +#define HAB_RVT_LOAD_DATA	0xc8
> +
> +#define HDR_SELF_PTR	0x14
> +#define HDR_BOOT_DATA	0x20
> +#define HDR_IMAGE_LEN	0x24
> +
> +#define L2X0_CTRL	0x100
> +#define SCU_CONFIG	0x004
> +
> +/*
> + * Disable L2 cache because ROM will turn it on when a plugin is used.
> + * There are cache coherence problems if cache is on when Linux kernel
> + * expects it to be off.
> + */
> +.macro disable_l2_cache
> +	ldr	r1, =L2_BASE_ADDR
> +	mov	r0, #0x0
> +	str	r0, [r1, #L2X0_CTRL]
> +.endm
> +
> +
> +/*
> + * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
> + */
> +plugin_start:
> +/* Save the return address and the function arguments */
> +	push	{r0-r8, lr}
> +
> +/* r0-r2 must be>= 0x100 and must be 4 byte aligned */
> +	cmp	r0, #0x100
> +	cmphs	r1, #0x100
> +	cmphs	r2, #0x100
> +
> +/* rCPU: 22 - mx6q, 12 - mx6dl, 12|0x100 - solo, 2 - sololite */
> +#define rCPU	r2
> +#define rIomux	r3
> +#define rVal0	r4	/* mx6q value */
> +#define rVal1	r5	/* mx6dl value */
> +#define rVal2	r6	/* mx6solo value */
> +#define rVal3	r7	/* mx6sololite value */
> +#define rFlag	lr
> +#define rTable	r8
> +
> +	orr	rFlag, r0, r1
> +	orr	rFlag, rFlag, r2
> +	orrlo	rFlag, rFlag, #1
> +
> +	mov	rCPU, #22		/* mx6q */
> +	mov	r1, #SCU_BASE_ADDR
> +	ldr	r0, [r1, #SCU_CONFIG]
> +	and	r0, r0, #3
> +	cmp	r0, #3			/* is mx6q? */
> +	movne	rCPU, #12		/* mx6dl */
> +	cmpne	r0, #1			/* is mx6dl? */
> +	movne	rCPU, #2		/* mx6 sololite */
> +
> +	ldrne	r1, =ANATOP_BASE_ADDR
> +	ldrne	r0, [r1, #0x280]
> +	movne	r0, r0, LSR #16
> +	cmpne	r0, #0x60		/* is mx6 Sololite? */
> +	movne	rCPU, #12 | 0x100	/* Solo */
> +
> +	mov	rVal0, #0
> +	mov	rVal1, #0
> +	mov	rVal2, #0
> +	mov	rVal3, #0
> +	ldr	rIomux, =IOMUXC_BASE_ADDR
> +	adr	rTable, mx6_table
> +	b	3f
> +
> +1:	movs	r0, r1, LSR #30
> +	beq	2f
> +	mov	r1, r1, LSL rCPU
> +	movs	r1, r1, LSR #32-10
> +	addne	r1, rIomux, r1, LSL #2
> +	cmp	r0, #3
> +	subne	r0, r0, #1
> +	orr	r1, r1, r0
> +
> +2:	ands	r0, r1, #3
> +	bic	r1, r1, #3
> +	ldrne	rVal0, [rTable], #4
> +	movne	rVal1, rVal0
> +	movne	rVal2, rVal0
> +	movne	rVal3, rVal0
> +	subnes	r0, r0, #1
> +	ldrne	rVal1, [rTable], #4
> +	movne	rVal2, rVal1
> +	movne	rVal3, rVal1
> +	subnes	r0, r0, #1
> +	ldrne	rVal2, [rTable], #4
> +	ldrne	rVal3, [rTable], #4
> +
> +	mov	r0, rVal0
> +	cmp	rCPU, #22
> +	movne	r0, rVal1
> +	cmpne	rCPU, #12
> +	movne	r0, rVal2
> +	cmpne	rCPU, #12|0x100
> +	movne	r0, rVal3
> +	cmp	r1, #0
> +	strne	r0, [r1]
> +3:	ldr	r1, [rTable], #4
> +	cmp	r1, #0
> +	bne	1b
> +
> +	tst	rFlag, #3
> +	bne	4f		/* Branch if not called as plugin */
> +/* Align end of table to 64 byte boundary */
> +	sub	rTable, rTable, #1
> +	orr	rTable, rTable, #0x3f
> +	add	rTable, rTable, #1
> +	ldr	r2, [rTable, #HDR_SELF_PTR]
> +	ldr	r0, [rTable, #HDR_BOOT_DATA]
> +	ldr	r1, [rTable, #HDR_IMAGE_LEN]
> +	sub	rTable, r2, r0
> +	mov	r2, r0
> +	mov	r3, r1
> +	mov	r4, #0
> +	push	{r0-r4}
> +	mov	r0, #HAB_RVT_LOAD_DATA
> +	ldr	r4, [r0]
> +	mov	r0, sp
> +	add	r1, sp, #4
> +	add	r2, sp, #8
> +	blx	r4
> +
> +	disable_l2_cache
> +	pop	{r4, r5}
> +	add	sp, sp, #12
> +	pop	{r0-r3}
> +/*
> + * Before returning to ROM, we need to fill the return values arguments
> + * to our function.
> + * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
> + */
> +
> +	str	r4, [r0]
> +	str	r5, [r1]
> +	str	rTable, [r2]
> +	mov	r0, #1
> +	pop	{r4-r8, pc}
> +
> +/* Not called as plugin */
> +4:	popne	{r0-r8, lr}
> +	mov	r0, #HAB_RVT_ENTRY
> +	ldr	lr, [r0]
> +	blx	lr
> +	mov	r0, #HAB_RVT_FAIL_SAFE_VECT
> +	ldr	lr, [r0]
> +	blx	lr
> +
> +	.ltorg
> +mx6_table:
> diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h
> index 8834c59..5c133b2 100644
> --- a/arch/arm/include/asm/arch-mx6/imx-regs.h
> +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h
> @@ -48,6 +48,7 @@
>   #define GLOBAL_TIMER_BASE_ADDR          0x00A00200
>   #define PRIVATE_TIMERS_WD_BASE_ADDR     0x00A00600
>   #define IC_DISTRIBUTOR_BASE_ADDR        0x00A01000
> +#define L2_BASE_ADDR                    0x00A02000
>   #define GPV0_BASE_ADDR                  0x00B00000
>   #define GPV1_BASE_ADDR                  0x00C00000
>   #define PCIE_ARB_BASE_ADDR              0x01000000
Stefano Babic Sept. 23, 2012, 10:17 a.m. UTC | #2
On 22/09/2012 04:39, Troy Kisky wrote:
> The "plugin" command of mkimage can take this
> file as an argument.
> 
> Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
> ---

Hi Troy,

I agree with Vikram that a better explanation of what a plugin is can
help to understand without reading deeply into the i.MX6 manual.

So a "plugin" is a chunk of code that can be called directly by the
BootROM of i.MX processors supporting V2 version of the i.MX header.
In my understanding, this is supported by i.MX53, too. After the plugin
run, the control is returned to the BootROM.

Now that we have some basis, why do we need this mechanism to boot this
board ? Is it not possible to make the same initialization directly in
u-boot ?

In principle, this adds stil some code that is not so easy to maintain.

>  arch/arm/cpu/armv7/mx6/Makefile          |    5 +-
>  arch/arm/cpu/armv7/mx6/plugin.S          |  164 ++++++++++++++++++++++++++++++
>  arch/arm/include/asm/arch-mx6/imx-regs.h |    1 +
>  3 files changed, 169 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/cpu/armv7/mx6/plugin.S
> 
> diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile
> index cbce411..b1fce4e 100644
> --- a/arch/arm/cpu/armv7/mx6/Makefile
> +++ b/arch/arm/cpu/armv7/mx6/Makefile
> @@ -33,11 +33,14 @@ SOBJS   = lowlevel_init.o
>  SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
>  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
>  
> -all:	$(obj).depend $(LIB)
> +all:	$(obj).depend $(LIB) plugin.bin
>  
>  $(LIB):	$(OBJS)
>  	$(call cmd_link_o_target, $(OBJS))
>  
> +plugin.bin: plugin.o
> +	$(OBJCOPY) -O binary --gap-fill 0xff $< $@

If we add a plugin mechanism, we can have several plugins (booting
directly from Net, maybe ?). We should then have a general mechanism. A
directory "plugins" here can contain the code, and it is compiled only
if a CONFIG_ is set or better if required from imximage.cfg


> +
>  #########################################################################
>  
>  # defines $(obj).depend target
> diff --git a/arch/arm/cpu/armv7/mx6/plugin.S b/arch/arm/cpu/armv7/mx6/plugin.S
> new file mode 100644
> index 0000000..99c6b20
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/mx6/plugin.S
> @@ -0,0 +1,164 @@
> +/*
> + * Copyright (C) 2012 Boundary Devices Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +#include <config.h>
> +#include <asm/arch/imx-regs.h>
> +
> +#define HAB_RVT_ENTRY		0x98
> +#define HAB_RVT_FAIL_SAFE_VECT	0xbc
> +#define HAB_RVT_LOAD_DATA	0xc8
> +
> +#define HDR_SELF_PTR	0x14
> +#define HDR_BOOT_DATA	0x20
> +#define HDR_IMAGE_LEN	0x24
> +
> +#define L2X0_CTRL	0x100
> +#define SCU_CONFIG	0x004
> +
> +/*
> + * Disable L2 cache because ROM will turn it on when a plugin is used.
> + * There are cache coherence problems if cache is on when Linux kernel
> + * expects it to be off.
> + */
> +.macro disable_l2_cache
> +	ldr	r1, =L2_BASE_ADDR
> +	mov	r0, #0x0
> +	str	r0, [r1, #L2X0_CTRL]
> +.endm
> +
> +
> +/*
> + * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
> + */
> +plugin_start:
> +/* Save the return address and the function arguments */
> +	push	{r0-r8, lr}
> +
> +/* r0-r2 must be  >= 0x100 and must be 4 byte aligned */
> +	cmp	r0, #0x100
> +	cmphs	r1, #0x100
> +	cmphs	r2, #0x100
> +
> +/* rCPU: 22 - mx6q, 12 - mx6dl, 12|0x100 - solo, 2 - sololite */
> +#define rCPU	r2
> +#define rIomux	r3
> +#define rVal0	r4	/* mx6q value */
> +#define rVal1	r5	/* mx6dl value */
> +#define rVal2	r6	/* mx6solo value */
> +#define rVal3	r7	/* mx6sololite value */
> +#define rFlag	lr
> +#define rTable	r8
> +
> +	orr	rFlag, r0, r1
> +	orr	rFlag, rFlag, r2
> +	orrlo	rFlag, rFlag, #1
> +
> +	mov	rCPU, #22		/* mx6q */
> +	mov	r1, #SCU_BASE_ADDR
> +	ldr	r0, [r1, #SCU_CONFIG]
> +	and	r0, r0, #3
> +	cmp	r0, #3			/* is mx6q? */
> +	movne	rCPU, #12		/* mx6dl */
> +	cmpne	r0, #1			/* is mx6dl? */
> +	movne	rCPU, #2		/* mx6 sololite */
> +
> +	ldrne	r1, =ANATOP_BASE_ADDR
> +	ldrne	r0, [r1, #0x280]
> +	movne	r0, r0, LSR #16
> +	cmpne	r0, #0x60		/* is mx6 Sololite? */
> +	movne	rCPU, #12 | 0x100	/* Solo */

Ok - until here you have checked which processor is running. Now the
more obscure code:

> +
> +	mov	rVal0, #0
> +	mov	rVal1, #0
> +	mov	rVal2, #0
> +	mov	rVal3, #0
> +	ldr	rIomux, =IOMUXC_BASE_ADDR
> +	adr	rTable, mx6_table
> +	b	3f



> +
> +1:	movs	r0, r1, LSR #30
> +	beq	2f
> +	mov	r1, r1, LSL rCPU
> +	movs	r1, r1, LSR #32-10
> +	addne	r1, rIomux, r1, LSL #2
> +	cmp	r0, #3
> +	subne	r0, r0, #1
> +	orr	r1, r1, r0
> +

The reason is to write GPR12 ? But why do we need a plugin for that ? I
do not understand why we cannot do it in the initialization code of the
SOC, as we usually do.

> +2:	ands	r0, r1, #3
> +	bic	r1, r1, #3
> +	ldrne	rVal0, [rTable], #4
> +	movne	rVal1, rVal0
> +	movne	rVal2, rVal0
> +	movne	rVal3, rVal0
> +	subnes	r0, r0, #1
> +	ldrne	rVal1, [rTable], #4
> +	movne	rVal2, rVal1
> +	movne	rVal3, rVal1
> +	subnes	r0, r0, #1
> +	ldrne	rVal2, [rTable], #4
> +	ldrne	rVal3, [rTable], #4
> +
> +	mov	r0, rVal0
> +	cmp	rCPU, #22
> +	movne	r0, rVal1
> +	cmpne	rCPU, #12
> +	movne	r0, rVal2
> +	cmpne	rCPU, #12|0x100
> +	movne	r0, rVal3
> +	cmp	r1, #0
> +	strne	r0, [r1]
> +3:	ldr	r1, [rTable], #4
> +	cmp	r1, #0
> +	bne	1b
> +
> +	tst	rFlag, #3
> +	bne	4f		/* Branch if not called as plugin */
> +/* Align end of table to 64 byte boundary */
> +	sub	rTable, rTable, #1
> +	orr	rTable, rTable, #0x3f
> +	add	rTable, rTable, #1
> +	ldr	r2, [rTable, #HDR_SELF_PTR]
> +	ldr	r0, [rTable, #HDR_BOOT_DATA]
> +	ldr	r1, [rTable, #HDR_IMAGE_LEN]
> +	sub	rTable, r2, r0
> +	mov	r2, r0
> +	mov	r3, r1
> +	mov	r4, #0
> +	push	{r0-r4}
> +	mov	r0, #HAB_RVT_LOAD_DATA
> +	ldr	r4, [r0]
> +	mov	r0, sp
> +	add	r1, sp, #4
> +	add	r2, sp, #8
> +	blx	r4

Sorry, I need help to understand this code

> +
> +	disable_l2_cache
> +	pop	{r4, r5}
> +	add	sp, sp, #12
> +	pop	{r0-r3}
> +/*
> + * Before returning to ROM, we need to fill the return values arguments
> + * to our function.
> + * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)

As the i.MX and the API suggest, it should be possible to write C code
for a plugin. Or am I wrong ?


> diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h
> index 8834c59..5c133b2 100644
> --- a/arch/arm/include/asm/arch-mx6/imx-regs.h
> +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h
> @@ -48,6 +48,7 @@
>  #define GLOBAL_TIMER_BASE_ADDR          0x00A00200
>  #define PRIVATE_TIMERS_WD_BASE_ADDR     0x00A00600
>  #define IC_DISTRIBUTOR_BASE_ADDR        0x00A01000
> +#define L2_BASE_ADDR                    0x00A02000
>  #define GPV0_BASE_ADDR                  0x00B00000
>  #define GPV1_BASE_ADDR                  0x00C00000
>  #define PCIE_ARB_BASE_ADDR              0x01000000
> 

This is useful in any case. I suggest you put this define in a separate
patch, that can flow independently into mainline.

Best regards,
Stefano Babic
Eric Nelson Sept. 23, 2012, 4:23 p.m. UTC | #3
On 09/23/2012 03:17 AM, Stefano Babic wrote:
> On 22/09/2012 04:39, Troy Kisky wrote:
>> The "plugin" command of mkimage can take this
>> file as an argument.
>>
>> Signed-off-by: Troy Kisky<troy.kisky@boundarydevices.com>
>> ---
>
> Hi Troy,
>
> I agree with Vikram that a better explanation of what a plugin is can
> help to understand without reading deeply into the i.MX6 manual.
>
> So a "plugin" is a chunk of code that can be called directly by the
> BootROM of i.MX processors supporting V2 version of the i.MX header.
> In my understanding, this is supported by i.MX53, too. After the plugin
> run, the control is returned to the BootROM.
>
Hi Stefano,

It seems that there's some general confusion on the list, so I think
a little more background and commentary is in order.

The primary rationale for plugins is to allow separate link maps in
a single image loaded by the BootROM.

The idea is to allow first-level code to initialize resources (usually
DDR) while running in internal RAM, then return to the boot rom for
further image loading (typically into DDR). This prevents the need
for the first-level code to support all boot sources (SPI-NOR,
NAND, SD card, etc) and allows it to focus on machine setup.

The feature is normally needed to allow the first level to access
a PMIC. I'm surprised that the 51evk and 53Loco boards aren't
using it.

Troy's rationale for using it now is to enable a single image on
i.MX6Quad, Dual lite and Solo processors, which have very slight
initialization differences. The 6Solo processor has 32-bit DDR
bus, so it would otherwise require a separate binary.

By doing this in code (plugin), we can introduce a conditional
based on processor type and have a single image that will boot
on any of the three.

The other key change for these processors is the location of
the iomux controller (moved on 6Solo/Duallite from 6Quad).

	6Solo has 32-bit DDR and iomux controller moved from 6Q
	6Duallite has 64-bit DDR but same iomux location as 6Q

Note that this highlights a slight down side to the plugin approach.

Because of the movement of the iomux controller, we can't use
a universal i.MX6 image header to write any IOMUX registers
through imximage.cfg.

Regards,


Eric
Stefano Babic Sept. 23, 2012, 5:08 p.m. UTC | #4
On 23/09/2012 18:23, Eric Nelson wrote:
> On 09/23/2012 03:17 AM, Stefano Babic wrote:
>> On 22/09/2012 04:39, Troy Kisky wrote:
>>> The "plugin" command of mkimage can take this
>>> file as an argument.
>>>
>>> Signed-off-by: Troy Kisky<troy.kisky@boundarydevices.com>
>>> ---
>>
>> Hi Troy,
>>
>> I agree with Vikram that a better explanation of what a plugin is can
>> help to understand without reading deeply into the i.MX6 manual.
>>
>> So a "plugin" is a chunk of code that can be called directly by the
>> BootROM of i.MX processors supporting V2 version of the i.MX header.
>> In my understanding, this is supported by i.MX53, too. After the plugin
>> run, the control is returned to the BootROM.
>>
> Hi Stefano,
> 
> It seems that there's some general confusion on the list, so I think
> a little more background and commentary is in order.

Well, it is - thanks for explanation.

> 
> The primary rationale for plugins is to allow separate link maps in
> a single image loaded by the BootROM.
> 
> The idea is to allow first-level code to initialize resources (usually
> DDR) while running in internal RAM, then return to the boot rom for
> further image loading (typically into DDR). This prevents the need
> for the first-level code to support all boot sources (SPI-NOR,
> NAND, SD card, etc) and allows it to focus on machine setup.
> 
> The feature is normally needed to allow the first level to access
> a PMIC. I'm surprised that the 51evk and 53Loco boards aren't
> using it.

The mx51 uses a V1 header and the plugin feature is not supported at
all. So, it can't, simply. The mx53 can, but it is not needed.
Both boards boot without plugin. So it seem we have a misunderstanding,
and thanks to raise this issue ;-)

The setup is done by the SOC interpreting the DCD data into the iMX
header. After this setup, that in any case cannot be very long, the
control is still taken by the bootROM, that copies data from the media
device to the DDR according to the values set into the iMX header. Still
without plugin. After the copy, the bootROM gives the control to U-Boot
for the rest that starts with the usual initialization.

There is no need to setup the pMIC on mx51evk and mx53qsb to get the DDR
running. However, even if we need it, we can do it in another way, as I
will explain now.

> 
> Troy's rationale for using it now is to enable a single image on
> i.MX6Quad, Dual lite and Solo processors, which have very slight
> initialization differences. The 6Solo processor has 32-bit DDR
> bus, so it would otherwise require a separate binary.
> 
> By doing this in code (plugin), we can introduce a conditional
> based on processor type and have a single image that will boot
> on any of the three.

Ok - but why cannot this check be done directly by U-Boot ?

My understanding is that you want to add a plugin written in assembly to
allow different setup of the DDR controller. Let's see how we can do
with standard U-Boot code.

Core of the startup is that the SOC copies itself some code into the
internal RAM and started. This is done by bootROM, running is own code
and running the plugin.

We have already this mechanism with the SPL framework. The big advantage
for this approach is that the same mechanism can be used on SOC of
different vendors, while the one in this series is a solution strictly
bound with (some) Freescale's SOC.

The imx header can be still adapted to copy the SPL code into the
internal RAM. When SPL is running, you have all freedom to check which
is the CPU running and to adjust your DDR setting, and everything is C
code. Both MX5 and MX6 have plenty of internal RAM to do this, because
SPL requires ~30KB.

I think the goal to have the same U-Boot binary can be reached using the
SPL framework. As you are running U-Boot code, you have the possibility
to do whatever you want.

So my question is: if the main reason is to have a single image for all
your iMX6 boards, why cannot we do it in a standard way using SPL ?

> 
> The other key change for these processors is the location of
> the iomux controller (moved on 6Solo/Duallite from 6Quad).
> 
>     6Solo has 32-bit DDR and iomux controller moved from 6Q
>     6Duallite has 64-bit DDR but same iomux location as 6Q
> 
> Note that this highlights a slight down side to the plugin approach.
> 
> Because of the movement of the iomux controller, we can't use
> a universal i.MX6 image header to write any IOMUX registers
> through imximage.cfg.

However, you can do it with this approach:

- you have a general imx header, that does not write into IOMUX
It is your choice if this should set the DDR or not. You could also
decide to have an empty DCD table.
- your imx Header is generated for your SPL code, and the destination
address for the SPL code is put into internal RAM
- the bootROM will start reading the iMX header and DCD data and copies
data from media (NAND, SPI, ..) into iRAM. There is no need for any
special setup because the iRAM is always available. Then it gives the
control to the SPL.
- the SPL starts and performs the setup of the DDR, checking the SOC if
it is required. The usual SOC initialization is done here.
- At the end, the SPL loads from media the U-Boot or directly the kernel
and starts it. Or whatever image you want.

The further advantage we can have with this approach is that we can
profit for further development in u-boot. What I mean really is using
TPL, that means putting u-boot into a UBL volume, see:

http://lists.celinuxforum.org/pipermail/celinux-dev/2012-April/000543.html

I know there is not yet activity on this topic, but it does not mean we
have not in future.

Best regards,
Stefano Babic
Eric Nelson Sept. 23, 2012, 11:29 p.m. UTC | #5
On 09/23/2012 10:08 AM, Stefano Babic wrote:
> On 23/09/2012 18:23, Eric Nelson wrote:
>> On 09/23/2012 03:17 AM, Stefano Babic wrote:
>>> On 22/09/2012 04:39, Troy Kisky wrote:
>>>> The "plugin" command of mkimage can take this
>>>> file as an argument.
>>>>
>>>> Signed-off-by: Troy Kisky<troy.kisky@boundarydevices.com>
>>>> ---
>>>
>>> Hi Troy,
>>>
>>> I agree with Vikram that a better explanation of what a plugin is can
>>> help to understand without reading deeply into the i.MX6 manual.
>>>
>>> So a "plugin" is a chunk of code that can be called directly by the
>>> BootROM of i.MX processors supporting V2 version of the i.MX header.
>>> In my understanding, this is supported by i.MX53, too. After the plugin
>>> run, the control is returned to the BootROM.
>>>
>> Hi Stefano,
>>
>> It seems that there's some general confusion on the list, so I think
>> a little more background and commentary is in order.
>
> Well, it is - thanks for explanation.
>
>>
>> The primary rationale for plugins is to allow separate link maps in
>> a single image loaded by the BootROM.
>>
>> The idea is to allow first-level code to initialize resources (usually
>> DDR) while running in internal RAM, then return to the boot rom for
>> further image loading (typically into DDR). This prevents the need
>> for the first-level code to support all boot sources (SPI-NOR,
>> NAND, SD card, etc) and allows it to focus on machine setup.
>>
>> The feature is normally needed to allow the first level to access
>> a PMIC. I'm surprised that the 51evk and 53Loco boards aren't
>> using it.
>
> The mx51 uses a V1 header and the plugin feature is not supported at
> all. So, it can't, simply. The mx53 can, but it is not needed.
> Both boards boot without plugin. So it seem we have a misunderstanding,
> and thanks to raise this issue ;-)
>
> The setup is done by the SOC interpreting the DCD data into the iMX
> header. After this setup, that in any case cannot be very long, the
> control is still taken by the bootROM, that copies data from the media
> device to the DDR according to the values set into the iMX header. Still
> without plugin. After the copy, the bootROM gives the control to U-Boot
> for the rest that starts with the usual initialization.
>
> There is no need to setup the pMIC on mx51evk and mx53qsb to get the DDR
> running. However, even if we need it, we can do it in another way, as I
> will explain now.
>
>>
>> Troy's rationale for using it now is to enable a single image on
>> i.MX6Quad, Dual lite and Solo processors, which have very slight
>> initialization differences. The 6Solo processor has 32-bit DDR
>> bus, so it would otherwise require a separate binary.
>>
>> By doing this in code (plugin), we can introduce a conditional
>> based on processor type and have a single image that will boot
>> on any of the three.
>
> Ok - but why cannot this check be done directly by U-Boot ?
>
> My understanding is that you want to add a plugin written in assembly to
> allow different setup of the DDR controller. Let's see how we can do
> with standard U-Boot code.
>
> Core of the startup is that the SOC copies itself some code into the
> internal RAM and started. This is done by bootROM, running is own code
> and running the plugin.
>
> We have already this mechanism with the SPL framework. The big advantage
> for this approach is that the same mechanism can be used on SOC of
> different vendors, while the one in this series is a solution strictly
> bound with (some) Freescale's SOC.
>
> The imx header can be still adapted to copy the SPL code into the
> internal RAM. When SPL is running, you have all freedom to check which
> is the CPU running and to adjust your DDR setting, and everything is C
> code. Both MX5 and MX6 have plenty of internal RAM to do this, because
> SPL requires ~30KB.
>

This is the part that gets interesting.

You're right that SPL **can** do the job, but only if it supports
the boot media. For the most part, it's reasonable to expect the
code to be written in U-Boot for that, since the boot media may
also be used to load kernels, RAM disks and the like.

But what about the serial boot modes (especially USB)? We likely
wouldn't implement them (we haven't yet pulled in USB slave support)
and to paraphrase US bumper stickers:

	You can take imx_usb away from me when you pry it
	from my cold dead hands ;)

If you're not aware of imx_usb, it's a utility that Troy wrote
to allow download over the boot ROM's USB protocol.

Some commentary is here:
	http://boundarydevices.com/unbricking-nitrogen6x-sabre-lite-i-mx6-board/

The sources are here (requires libusb):
	https://github.com/boundarydevices/imx_usb_loader

> I think the goal to have the same U-Boot binary can be reached using the
> SPL framework. As you are running U-Boot code, you have the possibility
> to do whatever you want.
>
> So my question is: if the main reason is to have a single image for all
> your iMX6 boards, why cannot we do it in a standard way using SPL ?
>

The related question is whether or not the benefits of a single
image is worth the carrying cost.

This is probably more useful for those who boot directly to
SD card, where the cost of creation or modification of the SD
card is high.

Since our boards are booting to SPI-NOR, I'm not completely
convinced.

It seems that simply creating three targets for each is okay, since
we know what processor we placed on the board and our boot mode
switches make it relatively easy to recover from a screw-up.

>>
>> The other key change for these processors is the location of
>> the iomux controller (moved on 6Solo/Duallite from 6Quad).
>>
>>      6Solo has 32-bit DDR and iomux controller moved from 6Q
>>      6Duallite has 64-bit DDR but same iomux location as 6Q
>>
>> Note that this highlights a slight down side to the plugin approach.
>>
>> Because of the movement of the iomux controller, we can't use
>> a universal i.MX6 image header to write any IOMUX registers
>> through imximage.cfg.
>
> However, you can do it with this approach:
>
> - you have a general imx header, that does not write into IOMUX
> It is your choice if this should set the DDR or not. You could also
> decide to have an empty DCD table.
> - your imx Header is generated for your SPL code, and the destination
> address for the SPL code is put into internal RAM
> - the bootROM will start reading the iMX header and DCD data and copies
> data from media (NAND, SPI, ..) into iRAM. There is no need for any
> special setup because the iRAM is always available. Then it gives the
> control to the SPL.
> - the SPL starts and performs the setup of the DDR, checking the SOC if
> it is required. The usual SOC initialization is done here.
> - At the end, the SPL loads from media the U-Boot or directly the kernel
> and starts it. Or whatever image you want.
>
> The further advantage we can have with this approach is that we can
> profit for further development in u-boot. What I mean really is using
> TPL, that means putting u-boot into a UBL volume, see:
>
> http://lists.celinuxforum.org/pipermail/celinux-dev/2012-April/000543.html
>
> I know there is not yet activity on this topic, but it does not mean we
> have not in future.
>

This is a good conversation to have.

Regards,


Eric
Stefano Babic Sept. 24, 2012, 7:22 a.m. UTC | #6
On 24/09/2012 01:29, Eric Nelson wrote:
> 
> This is the part that gets interesting.
> 
> You're right that SPL **can** do the job, but only if it supports
> the boot media. For the most part, it's reasonable to expect the
> code to be written in U-Boot for that, since the boot media may
> also be used to load kernels, RAM disks and the like.
> 
> But what about the serial boot modes (especially USB)? We likely
> wouldn't implement them (we haven't yet pulled in USB slave support)
> and to paraphrase US bumper stickers:
> 
>     You can take imx_usb away from me when you pry it
>     from my cold dead hands ;)
> 
> If you're not aware of imx_usb, it's a utility that Troy wrote
> to allow download over the boot ROM's USB protocol.
> 
> Some commentary is here:
>     http://boundarydevices.com/unbricking-nitrogen6x-sabre-lite-i-mx6-board/
> 
> 
> The sources are here (requires libusb):
>     https://github.com/boundarydevices/imx_usb_loader
> 

Nice job ! This is very valuable tool !

But I do not get the connection with the imximage and the need for the
plugin. If the SOC boots with "Serial Downloader", it polls the USB OTG
waiting for command as specified in the protocol. With your tool you set
the registers you need and you can download the file you want,
independently from the structure of the imxImage.

By the way, I have missed that Troy had implemented this tool - thanks
for the tipp and to share it !

>> I think the goal to have the same U-Boot binary can be reached using the
>> SPL framework. As you are running U-Boot code, you have the possibility
>> to do whatever you want.
>>
>> So my question is: if the main reason is to have a single image for all
>> your iMX6 boards, why cannot we do it in a standard way using SPL ?
>>
> 
> The related question is whether or not the benefits of a single
> image is worth the carrying cost.

I have interpreted from your answers that it was a goal for you. I think
the costs are higher than the benefits.

> 
> This is probably more useful for those who boot directly to
> SD card, where the cost of creation or modification of the SD
> card is high.
> 
> Since our boards are booting to SPI-NOR, I'm not completely
> convinced.
> 
> It seems that simply creating three targets for each is okay, since
> we know what processor we placed on the board and our boot mode
> switches make it relatively easy to recover from a screw-up.

Fully agree.

> 
>>>
>>> The other key change for these processors is the location of
>>> the iomux controller (moved on 6Solo/Duallite from 6Quad).
>>>
>>>      6Solo has 32-bit DDR and iomux controller moved from 6Q
>>>      6Duallite has 64-bit DDR but same iomux location as 6Q
>>>
>>> Note that this highlights a slight down side to the plugin approach.
>>>
>>> Because of the movement of the iomux controller, we can't use
>>> a universal i.MX6 image header to write any IOMUX registers
>>> through imximage.cfg.
>>
>> However, you can do it with this approach:
>>
>> - you have a general imx header, that does not write into IOMUX
>> It is your choice if this should set the DDR or not. You could also
>> decide to have an empty DCD table.
>> - your imx Header is generated for your SPL code, and the destination
>> address for the SPL code is put into internal RAM
>> - the bootROM will start reading the iMX header and DCD data and copies
>> data from media (NAND, SPI, ..) into iRAM. There is no need for any
>> special setup because the iRAM is always available. Then it gives the
>> control to the SPL.
>> - the SPL starts and performs the setup of the DDR, checking the SOC if
>> it is required. The usual SOC initialization is done here.
>> - At the end, the SPL loads from media the U-Boot or directly the kernel
>> and starts it. Or whatever image you want.
>>
>> The further advantage we can have with this approach is that we can
>> profit for further development in u-boot. What I mean really is using
>> TPL, that means putting u-boot into a UBL volume, see:
>>
>> http://lists.celinuxforum.org/pipermail/celinux-dev/2012-April/000543.html
>>
>>
>> I know there is not yet activity on this topic, but it does not mean we
>> have not in future.
>>
> 
> This is a good conversation to have.

Best regards,
Stefano
Eric Nelson Sept. 24, 2012, 1:48 p.m. UTC | #7
Hi Stefano,

On 09/24/2012 12:22 AM, Stefano Babic wrote:
> On 24/09/2012 01:29, Eric Nelson wrote:
>>
>> This is the part that gets interesting.
>>
>> You're right that SPL **can** do the job, but only if it supports
>> the boot media. For the most part, it's reasonable to expect the
>> code to be written in U-Boot for that, since the boot media may
>> also be used to load kernels, RAM disks and the like.
>>
>> But what about the serial boot modes (especially USB)? We likely
>> wouldn't implement them (we haven't yet pulled in USB slave support)
>> and to paraphrase US bumper stickers:
>>
>>      You can take imx_usb away from me when you pry it
>>      from my cold dead hands ;)
>>
>> If you're not aware of imx_usb, it's a utility that Troy wrote
>> to allow download over the boot ROM's USB protocol.
>>
>> Some commentary is here:
>>      http://boundarydevices.com/unbricking-nitrogen6x-sabre-lite-i-mx6-board/
>>
>>
>> The sources are here (requires libusb):
>>      https://github.com/boundarydevices/imx_usb_loader
>>
>
> Nice job ! This is very valuable tool !
>
> But I do not get the connection with the imximage and the need for the
> plugin. If the SOC boots with "Serial Downloader", it polls the USB OTG
> waiting for command as specified in the protocol. With your tool you set
> the registers you need and you can download the file you want,
> independently from the structure of the imxImage.
>

The relationship is this: if we build a combined SPL image for
a universal i.MX6 U-Boot, how would it know/decide that it's
being loaded via USB and how would it support this?

imx_usb supports plugins, so we can use it directly with that
approach.

> By the way, I have missed that Troy had implemented this tool - thanks
> for the tipp and to share it !
>

NP.

It really helps the compile/test cycle time, especially when used with the
'bmode usb' command.

>>> I think the goal to have the same U-Boot binary can be reached using the
>>> SPL framework. As you are running U-Boot code, you have the possibility
>>> to do whatever you want.
>>>
>>> So my question is: if the main reason is to have a single image for all
>>> your iMX6 boards, why cannot we do it in a standard way using SPL ?
>>>
>>
>> The related question is whether or not the benefits of a single
>> image is worth the carrying cost.
>
> I have interpreted from your answers that it was a goal for you. I think
> the costs are higher than the benefits.
>
>>
>> This is probably more useful for those who boot directly to
>> SD card, where the cost of creation or modification of the SD
>> card is high.
>>
>> Since our boards are booting to SPI-NOR, I'm not completely
>> convinced.
>>
>> It seems that simply creating three targets for each is okay, since
>> we know what processor we placed on the board and our boot mode
>> switches make it relatively easy to recover from a screw-up.
>
> Fully agree.
>
>>
>>>>
>>>> The other key change for these processors is the location of
>>>> the iomux controller (moved on 6Solo/Duallite from 6Quad).
>>>>
>>>>       6Solo has 32-bit DDR and iomux controller moved from 6Q
>>>>       6Duallite has 64-bit DDR but same iomux location as 6Q
>>>>
>>>> Note that this highlights a slight down side to the plugin approach.
>>>>
>>>> Because of the movement of the iomux controller, we can't use
>>>> a universal i.MX6 image header to write any IOMUX registers
>>>> through imximage.cfg.
>>>
>>> However, you can do it with this approach:
>>>
>>> - you have a general imx header, that does not write into IOMUX
>>> It is your choice if this should set the DDR or not. You could also
>>> decide to have an empty DCD table.
>>> - your imx Header is generated for your SPL code, and the destination
>>> address for the SPL code is put into internal RAM
>>> - the bootROM will start reading the iMX header and DCD data and copies
>>> data from media (NAND, SPI, ..) into iRAM. There is no need for any
>>> special setup because the iRAM is always available. Then it gives the
>>> control to the SPL.
>>> - the SPL starts and performs the setup of the DDR, checking the SOC if
>>> it is required. The usual SOC initialization is done here.
>>> - At the end, the SPL loads from media the U-Boot or directly the kernel
>>> and starts it. Or whatever image you want.
>>>
>>> The further advantage we can have with this approach is that we can
>>> profit for further development in u-boot. What I mean really is using
>>> TPL, that means putting u-boot into a UBL volume, see:
>>>
>>> http://lists.celinuxforum.org/pipermail/celinux-dev/2012-April/000543.html
>>>
>>>
>>> I know there is not yet activity on this topic, but it does not mean we
>>> have not in future.
>>>
>>
>> This is a good conversation to have.
>
> Best regards,
> Stefano
 >
Stefano Babic Sept. 24, 2012, 3:17 p.m. UTC | #8
On 24/09/2012 15:48, Eric Nelson wrote:
> Hi Stefano,
> 

Hi Eric,

>> But I do not get the connection with the imximage and the need for the
>> plugin. If the SOC boots with "Serial Downloader", it polls the USB OTG
>> waiting for command as specified in the protocol. With your tool you set
>> the registers you need and you can download the file you want,
>> independently from the structure of the imxImage.
>>
> 
> The relationship is this: if we build a combined SPL image for
> a universal i.MX6 U-Boot, how would it know/decide that it's
> being loaded via USB and how would it support this?
> 
> imx_usb supports plugins, so we can use it directly with that
> approach.

But this seems to me an implementation choice rather a constraint of the
SOC. As I see in your code, imx_usb parses the iMX header making
decisions according to it. Then there is a hard dependency between
imx_usb and u-boot code.

The other way is that they are independently, let's say, openOCD
approach ;-).

imx_usb could get an independent file to configure the DDR controller
(for example, but it is not limited to), and then load a u-boot (or SPL,
or...) where you want. Then there is no strict dependency with the
imx_usb tool. The SOC allows this approach, too.

Best regards,
Stefano
Troy Kisky Sept. 24, 2012, 8:46 p.m. UTC | #9
On 9/23/2012 3:17 AM, Stefano Babic wrote:
> On 22/09/2012 04:39, Troy Kisky wrote:
>> The "plugin" command of mkimage can take this
>> file as an argument.
>>
>> Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
>> ---
> Hi Troy,
>
> I agree with Vikram that a better explanation of what a plugin is can
> help to understand without reading deeply into the i.MX6 manual.
>
> So a "plugin" is a chunk of code that can be called directly by the
> BootROM of i.MX processors supporting V2 version of the i.MX header.
> In my understanding, this is supported by i.MX53, too. After the plugin
> run, the control is returned to the BootROM.
>
> Now that we have some basis, why do we need this mechanism to boot this
> board ? Is it not possible to make the same initialization directly in
> u-boot ?
>
> In principle, this adds stil some code that is not so easy to maintain.

I can add to README.imximage. But I'm beginning to doubt if plugins are 
going
to be accepted at all.

>
>>   arch/arm/cpu/armv7/mx6/Makefile          |    5 +-
>>   arch/arm/cpu/armv7/mx6/plugin.S          |  164 ++++++++++++++++++++++++++++++
>>   arch/arm/include/asm/arch-mx6/imx-regs.h |    1 +
>>   3 files changed, 169 insertions(+), 1 deletion(-)
>>   create mode 100644 arch/arm/cpu/armv7/mx6/plugin.S
>>
>> diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile
>> index cbce411..b1fce4e 100644
>> --- a/arch/arm/cpu/armv7/mx6/Makefile
>> +++ b/arch/arm/cpu/armv7/mx6/Makefile
>> @@ -33,11 +33,14 @@ SOBJS   = lowlevel_init.o
>>   SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
>>   OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
>>   
>> -all:	$(obj).depend $(LIB)
>> +all:	$(obj).depend $(LIB) plugin.bin
>>   
>>   $(LIB):	$(OBJS)
>>   	$(call cmd_link_o_target, $(OBJS))
>>   
>> +plugin.bin: plugin.o
>> +	$(OBJCOPY) -O binary --gap-fill 0xff $< $@
> If we add a plugin mechanism, we can have several plugins (booting
> directly from Net, maybe ?). We should then have a general mechanism. A
> directory "plugins" here can contain the code, and it is compiled only
> if a CONFIG_ is set or better if required from imximage.cfg

CONFIG_xx I understand, but can you describe an implementation from 
imximage.cfg?


>
>
>> +
>>   #########################################################################
>>   
>>   # defines $(obj).depend target
>> diff --git a/arch/arm/cpu/armv7/mx6/plugin.S b/arch/arm/cpu/armv7/mx6/plugin.S
>> new file mode 100644
>> index 0000000..99c6b20
>> --- /dev/null
>> +++ b/arch/arm/cpu/armv7/mx6/plugin.S
>> @@ -0,0 +1,164 @@
>> +/*
>> + * Copyright (C) 2012 Boundary Devices Inc.
>> + *
>> + * Licensed under the GPL-2 or later.
>> + */
>> +#include <config.h>
>> +#include <asm/arch/imx-regs.h>
>> +
>> +#define HAB_RVT_ENTRY		0x98
>> +#define HAB_RVT_FAIL_SAFE_VECT	0xbc
>> +#define HAB_RVT_LOAD_DATA	0xc8
>> +
>> +#define HDR_SELF_PTR	0x14
>> +#define HDR_BOOT_DATA	0x20
>> +#define HDR_IMAGE_LEN	0x24
>> +
>> +#define L2X0_CTRL	0x100
>> +#define SCU_CONFIG	0x004
>> +
>> +/*
>> + * Disable L2 cache because ROM will turn it on when a plugin is used.
>> + * There are cache coherence problems if cache is on when Linux kernel
>> + * expects it to be off.
>> + */
>> +.macro disable_l2_cache
>> +	ldr	r1, =L2_BASE_ADDR
>> +	mov	r0, #0x0
>> +	str	r0, [r1, #L2X0_CTRL]
>> +.endm
>> +
>> +
>> +/*
>> + * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
>> + */
>> +plugin_start:
>> +/* Save the return address and the function arguments */
>> +	push	{r0-r8, lr}
>> +
>> +/* r0-r2 must be  >= 0x100 and must be 4 byte aligned */
>> +	cmp	r0, #0x100
>> +	cmphs	r1, #0x100
>> +	cmphs	r2, #0x100
>> +
>> +/* rCPU: 22 - mx6q, 12 - mx6dl, 12|0x100 - solo, 2 - sololite */
>> +#define rCPU	r2
>> +#define rIomux	r3
>> +#define rVal0	r4	/* mx6q value */
>> +#define rVal1	r5	/* mx6dl value */
>> +#define rVal2	r6	/* mx6solo value */
>> +#define rVal3	r7	/* mx6sololite value */
>> +#define rFlag	lr
>> +#define rTable	r8
>> +
>> +	orr	rFlag, r0, r1
>> +	orr	rFlag, rFlag, r2
>> +	orrlo	rFlag, rFlag, #1
>> +
>> +	mov	rCPU, #22		/* mx6q */
>> +	mov	r1, #SCU_BASE_ADDR
>> +	ldr	r0, [r1, #SCU_CONFIG]
>> +	and	r0, r0, #3
>> +	cmp	r0, #3			/* is mx6q? */
>> +	movne	rCPU, #12		/* mx6dl */
>> +	cmpne	r0, #1			/* is mx6dl? */
>> +	movne	rCPU, #2		/* mx6 sololite */
>> +
>> +	ldrne	r1, =ANATOP_BASE_ADDR
>> +	ldrne	r0, [r1, #0x280]
>> +	movne	r0, r0, LSR #16
>> +	cmpne	r0, #0x60		/* is mx6 Sololite? */
>> +	movne	rCPU, #12 | 0x100	/* Solo */
> Ok - until here you have checked which processor is running. Now the
> more obscure code:
>
>> +
>> +	mov	rVal0, #0
>> +	mov	rVal1, #0
>> +	mov	rVal2, #0
>> +	mov	rVal3, #0
>> +	ldr	rIomux, =IOMUXC_BASE_ADDR
>> +	adr	rTable, mx6_table
>> +	b	3f
>
>
>> +
>> +1:	movs	r0, r1, LSR #30
>> +	beq	2f
>> +	mov	r1, r1, LSL rCPU
>> +	movs	r1, r1, LSR #32-10
>> +	addne	r1, rIomux, r1, LSL #2
>> +	cmp	r0, #3
>> +	subne	r0, r0, #1
>> +	orr	r1, r1, r0
>> +
> The reason is to write GPR12 ? But why do we need a plugin for that ? I
> do not understand why we cannot do it in the initialization code of the
> SOC, as we usually do.

This is not GPR12.  The address value from the cfg file is actually 3 
addresses. One for
mx6q, one for mx6 duallite/solo, one for mx6 sololite. Each is specified 
as a 10 bit
field which we use as a 12 bit offset within IOMUXC_BASE_ADDR (A0/A1 
forced to 0).


>
>> +2:	ands	r0, r1, #3
>> +	bic	r1, r1, #3
>> +	ldrne	rVal0, [rTable], #4
>> +	movne	rVal1, rVal0
>> +	movne	rVal2, rVal0
>> +	movne	rVal3, rVal0
>> +	subnes	r0, r0, #1
>> +	ldrne	rVal1, [rTable], #4
>> +	movne	rVal2, rVal1
>> +	movne	rVal3, rVal1
>> +	subnes	r0, r0, #1
>> +	ldrne	rVal2, [rTable], #4
>> +	ldrne	rVal3, [rTable], #4
>> +
>> +	mov	r0, rVal0
>> +	cmp	rCPU, #22
>> +	movne	r0, rVal1
>> +	cmpne	rCPU, #12
>> +	movne	r0, rVal2
>> +	cmpne	rCPU, #12|0x100
>> +	movne	r0, rVal3
>> +	cmp	r1, #0
>> +	strne	r0, [r1]
>> +3:	ldr	r1, [rTable], #4
>> +	cmp	r1, #0
>> +	bne	1b
>> +
>> +	tst	rFlag, #3
>> +	bne	4f		/* Branch if not called as plugin */
>> +/* Align end of table to 64 byte boundary */
>> +	sub	rTable, rTable, #1
>> +	orr	rTable, rTable, #0x3f
>> +	add	rTable, rTable, #1
>> +	ldr	r2, [rTable, #HDR_SELF_PTR]
>> +	ldr	r0, [rTable, #HDR_BOOT_DATA]
>> +	ldr	r1, [rTable, #HDR_IMAGE_LEN]
>> +	sub	rTable, r2, r0
>> +	mov	r2, r0
>> +	mov	r3, r1
>> +	mov	r4, #0
>> +	push	{r0-r4}
>> +	mov	r0, #HAB_RVT_LOAD_DATA
>> +	ldr	r4, [r0]
>> +	mov	r0, sp
>> +	add	r1, sp, #4
>> +	add	r2, sp, #8
>> +	blx	r4
> Sorry, I need help to understand this code

Now that DDR is initialized, this is calling back into the ROM code
so that it can finish loading u-boot.

>
>> +
>> +	disable_l2_cache
>> +	pop	{r4, r5}
>> +	add	sp, sp, #12
>> +	pop	{r0-r3}
>> +/*
>> + * Before returning to ROM, we need to fill the return values arguments
>> + * to our function.
>> + * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
> As the i.MX and the API suggest, it should be possible to write C code
> for a plugin. Or am I wrong ?


I don't see why not. But this code is currently position independent. It 
would be nice to maintain that.

>
>
>> diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h
>> index 8834c59..5c133b2 100644
>> --- a/arch/arm/include/asm/arch-mx6/imx-regs.h
>> +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h
>> @@ -48,6 +48,7 @@
>>   #define GLOBAL_TIMER_BASE_ADDR          0x00A00200
>>   #define PRIVATE_TIMERS_WD_BASE_ADDR     0x00A00600
>>   #define IC_DISTRIBUTOR_BASE_ADDR        0x00A01000
>> +#define L2_BASE_ADDR                    0x00A02000
>>   #define GPV0_BASE_ADDR                  0x00B00000
>>   #define GPV1_BASE_ADDR                  0x00C00000
>>   #define PCIE_ARB_BASE_ADDR              0x01000000
>>
> This is useful in any case. I suggest you put this define in a separate
> patch, that can flow independently into mainline.
>
> Best regards,
> Stefano Babic
>

Hmm, do you suggest moving the L2 disable code to another spot as well ?
Troy Kisky Sept. 24, 2012, 10:23 p.m. UTC | #10
On 9/23/2012 10:08 AM, Stefano Babic wrote:
> On 23/09/2012 18:23, Eric Nelson wrote:
>> On 09/23/2012 03:17 AM, Stefano Babic wrote:
>>> On 22/09/2012 04:39, Troy Kisky wrote:
>>>> The "plugin" command of mkimage can take this
>>>> file as an argument.
>>>>
>>>> Signed-off-by: Troy Kisky<troy.kisky@boundarydevices.com>
>>>> ---
>>> Hi Troy,
>>>
>>> I agree with Vikram that a better explanation of what a plugin is can
>>> help to understand without reading deeply into the i.MX6 manual.
>>>
>>> So a "plugin" is a chunk of code that can be called directly by the
>>> BootROM of i.MX processors supporting V2 version of the i.MX header.
>>> In my understanding, this is supported by i.MX53, too. After the plugin
>>> run, the control is returned to the BootROM.
>>>
>> Hi Stefano,
>>
>> It seems that there's some general confusion on the list, so I think
>> a little more background and commentary is in order.
> Well, it is - thanks for explanation.
>
>> The primary rationale for plugins is to allow separate link maps in
>> a single image loaded by the BootROM.
>>
>> The idea is to allow first-level code to initialize resources (usually
>> DDR) while running in internal RAM, then return to the boot rom for
>> further image loading (typically into DDR). This prevents the need
>> for the first-level code to support all boot sources (SPI-NOR,
>> NAND, SD card, etc) and allows it to focus on machine setup.
>>
>> The feature is normally needed to allow the first level to access
>> a PMIC. I'm surprised that the 51evk and 53Loco boards aren't
>> using it.
> The mx51 uses a V1 header and the plugin feature is not supported at
> all. So, it can't, simply. The mx53 can, but it is not needed.
> Both boards boot without plugin. So it seem we have a misunderstanding,
> and thanks to raise this issue ;-)
>
> The setup is done by the SOC interpreting the DCD data into the iMX
> header. After this setup, that in any case cannot be very long, the
> control is still taken by the bootROM, that copies data from the media
> device to the DDR according to the values set into the iMX header. Still
> without plugin. After the copy, the bootROM gives the control to U-Boot
> for the rest that starts with the usual initialization.
>
> There is no need to setup the pMIC on mx51evk and mx53qsb to get the DDR
> running. However, even if we need it, we can do it in another way, as I
> will explain now.
>
>> Troy's rationale for using it now is to enable a single image on
>> i.MX6Quad, Dual lite and Solo processors, which have very slight
>> initialization differences. The 6Solo processor has 32-bit DDR
>> bus, so it would otherwise require a separate binary.
>>
>> By doing this in code (plugin), we can introduce a conditional
>> based on processor type and have a single image that will boot
>> on any of the three.
> Ok - but why cannot this check be done directly by U-Boot ?
>
> My understanding is that you want to add a plugin written in assembly to
> allow different setup of the DDR controller. Let's see how we can do
> with standard U-Boot code.
>
> Core of the startup is that the SOC copies itself some code into the
> internal RAM and started. This is done by bootROM, running is own code
> and running the plugin.
>
> We have already this mechanism with the SPL framework. The big advantage
> for this approach is that the same mechanism can be used on SOC of
> different vendors, while the one in this series is a solution strictly
> bound with (some) Freescale's SOC.
>
> The imx header can be still adapted to copy the SPL code into the
> internal RAM. When SPL is running, you have all freedom to check which
> is the CPU running and to adjust your DDR setting, and everything is C
> code. Both MX5 and MX6 have plenty of internal RAM to do this, because
> SPL requires ~30KB.
>
> I think the goal to have the same U-Boot binary can be reached using the
> SPL framework. As you are running U-Boot code, you have the possibility
> to do whatever you want.
>
> So my question is: if the main reason is to have a single image for all
> your iMX6 boards, why cannot we do it in a standard way using SPL ?
>
>> The other key change for these processors is the location of
>> the iomux controller (moved on 6Solo/Duallite from 6Quad).
>>
>>      6Solo has 32-bit DDR and iomux controller moved from 6Q
>>      6Duallite has 64-bit DDR but same iomux location as 6Q
>>
>> Note that this highlights a slight down side to the plugin approach.
>>
>> Because of the movement of the iomux controller, we can't use
>> a universal i.MX6 image header to write any IOMUX registers
>> through imximage.cfg.
> However, you can do it with this approach:
>
> - you have a general imx header, that does not write into IOMUX
> It is your choice if this should set the DDR or not. You could also
> decide to have an empty DCD table.
> - your imx Header is generated for your SPL code, and the destination
> address for the SPL code is put into internal RAM
> - the bootROM will start reading the iMX header and DCD data and copies
> data from media (NAND, SPI, ..) into iRAM. There is no need for any
> special setup because the iRAM is always available. Then it gives the
> control to the SPL.
> - the SPL starts and performs the setup of the DDR, checking the SOC if
> it is required. The usual SOC initialization is done here.
> - At the end, the SPL loads from media the U-Boot or directly the kernel
> and starts it. Or whatever image you want.
>
> The further advantage we can have with this approach is that we can
> profit for further development in u-boot. What I mean really is using
> TPL, that means putting u-boot into a UBL volume, see:
>
> http://lists.celinuxforum.org/pipermail/celinux-dev/2012-April/000543.html
>
> I know there is not yet activity on this topic, but it does not mean we
> have not in future.
>
> Best regards,
> Stefano Babic
>
The advantages of a plugin over spl are
1. smaller code 0x190 bytes, plus the table.
relying on the ROM to do the heavy lifting.

2. support all boot modes that the ROM does.
     NOR/NAND/ONENAND/MMC/eMMC
  Hard Disk and SSD devices using SATA
Serial ROM through SPI/I2C

3. Easy to switch back to previous DCD tables
for debugging or permanently. I can see that many
people will never use either plugin or SPL and will stick
with the current method, or have separate cfg
files for each processor type. I could still have
the separate cfg files #include a common file.
ie
#define FOR_MX6Q
#include "imx-common.cfg"
------------
#define FOR_MX6DL
#include "imx-common.cfg"

4. plugin method is already working.




Let me know which features might make it to mainline
1. variable length headers
2. parsing of cfg to pull the file, instead of push
3. C preprocessor
4. expression evaluation.
5 plugins

and I'll post a new series.

Thanks
Troy
Stefano Babic Sept. 25, 2012, 11:57 a.m. UTC | #11
On 24/09/2012 22:46, Troy Kisky wrote:
> On 9/23/2012 3:17 AM, Stefano Babic wrote:
>> On 22/09/2012 04:39, Troy Kisky wrote:
>>> The "plugin" command of mkimage can take this
>>> file as an argument.
>>>
>>> Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
>>> ---

Hi Troy,

>>
>> I agree with Vikram that a better explanation of what a plugin is can
>> help to understand without reading deeply into the i.MX6 manual.
>>
>> So a "plugin" is a chunk of code that can be called directly by the
>> BootROM of i.MX processors supporting V2 version of the i.MX header.
>> In my understanding, this is supported by i.MX53, too. After the plugin
>> run, the control is returned to the BootROM.
>>
>> Now that we have some basis, why do we need this mechanism to boot this
>> board ? Is it not possible to make the same initialization directly in
>> u-boot ?
>>
>> In principle, this adds stil some code that is not so easy to maintain.
> 
> I can add to README.imximage. But I'm beginning to doubt if plugins are
> going
> to be accepted at all.

I have several doubts about using the plugin. First at all, this make
the development of new iMX completely different as the rest of U-boot.
Plugin ist a feature so strictly bounded to the Freescale's iMX. The
risk here is that U-Boot imx diverges from the other SOCs, while we are
currently in a phase where we want to uniform as much as possible the
behavior with different architectures.

I am also not convinced why introducing the plugin is strictly required.
Reading Eric's answer, I get that costs for having and maintaing a
single image U-boot for different boards overcomes the benefits, and I
fully agree with him. But reading your patch and from your explanation
of plugin code, I understand that the plugin is used to detect which CPU
is running, and then to set differently registers, because offsets are
different. So the goal is again to have a single image.

>>> +
>>> +1:    movs    r0, r1, LSR #30
>>> +    beq    2f
>>> +    mov    r1, r1, LSL rCPU
>>> +    movs    r1, r1, LSR #32-10
>>> +    addne    r1, rIomux, r1, LSL #2
>>> +    cmp    r0, #3
>>> +    subne    r0, r0, #1
>>> +    orr    r1, r1, r0
>>> +
>> The reason is to write GPR12 ? But why do we need a plugin for that ? I
>> do not understand why we cannot do it in the initialization code of the
>> SOC, as we usually do.
> 
> This is not GPR12.  The address value from the cfg file is actually 3
> addresses. One for
> mx6q, one for mx6 duallite/solo, one for mx6 sololite. Each is specified
> as a 10 bit
> field which we use as a 12 bit offset within IOMUXC_BASE_ADDR (A0/A1
> forced to 0).

Ok, thanks for explanation - I had not understood before.


>>> @@ -48,6 +48,7 @@
>>>   #define GLOBAL_TIMER_BASE_ADDR          0x00A00200
>>>   #define PRIVATE_TIMERS_WD_BASE_ADDR     0x00A00600
>>>   #define IC_DISTRIBUTOR_BASE_ADDR        0x00A01000
>>> +#define L2_BASE_ADDR                    0x00A02000
>>>   #define GPV0_BASE_ADDR                  0x00B00000
>>>   #define GPV1_BASE_ADDR                  0x00C00000
>>>   #define PCIE_ARB_BASE_ADDR              0x01000000
>>>
>> This is useful in any case. I suggest you put this define in a separate
>> patch, that can flow independently into mainline.

> Hmm, do you suggest moving the L2 disable code to another spot as well ?

Easier - I suggest you put this define in a separate patch, because it
can be accessed by other U-Boot code as well.

Best regards,
Stefano Babic
Stefano Babic Sept. 25, 2012, 12:13 p.m. UTC | #12
On 25/09/2012 00:23, Troy Kisky wrote:
> The advantages of a plugin over spl are
> 1. smaller code 0x190 bytes, plus the table.
> relying on the ROM to do the heavy lifting.

This is true. However, as you are writing in the next line, the bootROM
boots from devices having much more space as some bytes. Even on small
SPI-NOR (the smallest device I used with MX5), this was not an issue.

On the other side, you cannot influence the behavior of the bootROM, and
much more job is let to the bootROM, less possibilities to fix some
things. SPL is part of U-Boot, all sources are availbale and it is
easier to fix.

> 
> 2. support all boot modes that the ROM does.
>     NOR/NAND/ONENAND/MMC/eMMC
>  Hard Disk and SSD devices using SATA
> Serial ROM through SPI/I2C

I do not know about booting from SATA, if a plugin is a must - but this
means that it fixes a problem in the bootROM.
Apart of that, there are no hardware limitation that avoi to use SPL
with these media devices.

> 3. Easy to switch back to previous DCD tables
> for debugging or permanently. I can see that many
> people will never use either plugin or SPL

I think you are talking specifically about mainlined i.MX boards. This
is correct, because patches to make SPL available will be merged now.
But if we see U-Boot in its globality, quite all TI's boards have a SPL.

> and will stick
> with the current method, or have separate cfg
> files for each processor type. I could still have
> the separate cfg files #include a common file.
> ie
> #define FOR_MX6Q
> #include "imx-common.cfg"

Using common file is a practice we should improve, definitely. But it
has nothing to do with plugin. Agree that similar boards and / or SOCs
should better share code.

> ------------
> #define FOR_MX6DL
> #include "imx-common.cfg"
> 
> 4. plugin method is already working.

ok, this is right

> Let me know which features might make it to mainline
> 1. variable length headers

Absolutely yes !

> 2. parsing of cfg to pull the file, instead of push
> 3. C preprocessor

Yes, I agree with you that it is useful. As you said, using #define make
it more readable.

> 4. expression evaluation.

As you posted previously, this depends on plugin.

> 5 plugins

Currently, I do not see that plugin is strictly required and can move
iMX away from the rest of U-Boot development.


> 
> and I'll post a new series.

Ok, thanks.

Best regards,
Stefano
diff mbox

Patch

diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile
index cbce411..b1fce4e 100644
--- a/arch/arm/cpu/armv7/mx6/Makefile
+++ b/arch/arm/cpu/armv7/mx6/Makefile
@@ -33,11 +33,14 @@  SOBJS   = lowlevel_init.o
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
 
-all:	$(obj).depend $(LIB)
+all:	$(obj).depend $(LIB) plugin.bin
 
 $(LIB):	$(OBJS)
 	$(call cmd_link_o_target, $(OBJS))
 
+plugin.bin: plugin.o
+	$(OBJCOPY) -O binary --gap-fill 0xff $< $@
+
 #########################################################################
 
 # defines $(obj).depend target
diff --git a/arch/arm/cpu/armv7/mx6/plugin.S b/arch/arm/cpu/armv7/mx6/plugin.S
new file mode 100644
index 0000000..99c6b20
--- /dev/null
+++ b/arch/arm/cpu/armv7/mx6/plugin.S
@@ -0,0 +1,164 @@ 
+/*
+ * Copyright (C) 2012 Boundary Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#include <config.h>
+#include <asm/arch/imx-regs.h>
+
+#define HAB_RVT_ENTRY		0x98
+#define HAB_RVT_FAIL_SAFE_VECT	0xbc
+#define HAB_RVT_LOAD_DATA	0xc8
+
+#define HDR_SELF_PTR	0x14
+#define HDR_BOOT_DATA	0x20
+#define HDR_IMAGE_LEN	0x24
+
+#define L2X0_CTRL	0x100
+#define SCU_CONFIG	0x004
+
+/*
+ * Disable L2 cache because ROM will turn it on when a plugin is used.
+ * There are cache coherence problems if cache is on when Linux kernel
+ * expects it to be off.
+ */
+.macro disable_l2_cache
+	ldr	r1, =L2_BASE_ADDR
+	mov	r0, #0x0
+	str	r0, [r1, #L2X0_CTRL]
+.endm
+
+
+/*
+ * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
+ */
+plugin_start:
+/* Save the return address and the function arguments */
+	push	{r0-r8, lr}
+
+/* r0-r2 must be  >= 0x100 and must be 4 byte aligned */
+	cmp	r0, #0x100
+	cmphs	r1, #0x100
+	cmphs	r2, #0x100
+
+/* rCPU: 22 - mx6q, 12 - mx6dl, 12|0x100 - solo, 2 - sololite */
+#define rCPU	r2
+#define rIomux	r3
+#define rVal0	r4	/* mx6q value */
+#define rVal1	r5	/* mx6dl value */
+#define rVal2	r6	/* mx6solo value */
+#define rVal3	r7	/* mx6sololite value */
+#define rFlag	lr
+#define rTable	r8
+
+	orr	rFlag, r0, r1
+	orr	rFlag, rFlag, r2
+	orrlo	rFlag, rFlag, #1
+
+	mov	rCPU, #22		/* mx6q */
+	mov	r1, #SCU_BASE_ADDR
+	ldr	r0, [r1, #SCU_CONFIG]
+	and	r0, r0, #3
+	cmp	r0, #3			/* is mx6q? */
+	movne	rCPU, #12		/* mx6dl */
+	cmpne	r0, #1			/* is mx6dl? */
+	movne	rCPU, #2		/* mx6 sololite */
+
+	ldrne	r1, =ANATOP_BASE_ADDR
+	ldrne	r0, [r1, #0x280]
+	movne	r0, r0, LSR #16
+	cmpne	r0, #0x60		/* is mx6 Sololite? */
+	movne	rCPU, #12 | 0x100	/* Solo */
+
+	mov	rVal0, #0
+	mov	rVal1, #0
+	mov	rVal2, #0
+	mov	rVal3, #0
+	ldr	rIomux, =IOMUXC_BASE_ADDR
+	adr	rTable, mx6_table
+	b	3f
+
+1:	movs	r0, r1, LSR #30
+	beq	2f
+	mov	r1, r1, LSL rCPU
+	movs	r1, r1, LSR #32-10
+	addne	r1, rIomux, r1, LSL #2
+	cmp	r0, #3
+	subne	r0, r0, #1
+	orr	r1, r1, r0
+
+2:	ands	r0, r1, #3
+	bic	r1, r1, #3
+	ldrne	rVal0, [rTable], #4
+	movne	rVal1, rVal0
+	movne	rVal2, rVal0
+	movne	rVal3, rVal0
+	subnes	r0, r0, #1
+	ldrne	rVal1, [rTable], #4
+	movne	rVal2, rVal1
+	movne	rVal3, rVal1
+	subnes	r0, r0, #1
+	ldrne	rVal2, [rTable], #4
+	ldrne	rVal3, [rTable], #4
+
+	mov	r0, rVal0
+	cmp	rCPU, #22
+	movne	r0, rVal1
+	cmpne	rCPU, #12
+	movne	r0, rVal2
+	cmpne	rCPU, #12|0x100
+	movne	r0, rVal3
+	cmp	r1, #0
+	strne	r0, [r1]
+3:	ldr	r1, [rTable], #4
+	cmp	r1, #0
+	bne	1b
+
+	tst	rFlag, #3
+	bne	4f		/* Branch if not called as plugin */
+/* Align end of table to 64 byte boundary */
+	sub	rTable, rTable, #1
+	orr	rTable, rTable, #0x3f
+	add	rTable, rTable, #1
+	ldr	r2, [rTable, #HDR_SELF_PTR]
+	ldr	r0, [rTable, #HDR_BOOT_DATA]
+	ldr	r1, [rTable, #HDR_IMAGE_LEN]
+	sub	rTable, r2, r0
+	mov	r2, r0
+	mov	r3, r1
+	mov	r4, #0
+	push	{r0-r4}
+	mov	r0, #HAB_RVT_LOAD_DATA
+	ldr	r4, [r0]
+	mov	r0, sp
+	add	r1, sp, #4
+	add	r2, sp, #8
+	blx	r4
+
+	disable_l2_cache
+	pop	{r4, r5}
+	add	sp, sp, #12
+	pop	{r0-r3}
+/*
+ * Before returning to ROM, we need to fill the return values arguments
+ * to our function.
+ * plugin_start(void **start, size_t *bytes, UINT32 *ivt_offset)
+ */
+
+	str	r4, [r0]
+	str	r5, [r1]
+	str	rTable, [r2]
+	mov	r0, #1
+	pop	{r4-r8, pc}
+
+/* Not called as plugin */
+4:	popne	{r0-r8, lr}
+	mov	r0, #HAB_RVT_ENTRY
+	ldr	lr, [r0]
+	blx	lr
+	mov	r0, #HAB_RVT_FAIL_SAFE_VECT
+	ldr	lr, [r0]
+	blx	lr
+
+	.ltorg
+mx6_table:
diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h
index 8834c59..5c133b2 100644
--- a/arch/arm/include/asm/arch-mx6/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx6/imx-regs.h
@@ -48,6 +48,7 @@ 
 #define GLOBAL_TIMER_BASE_ADDR          0x00A00200
 #define PRIVATE_TIMERS_WD_BASE_ADDR     0x00A00600
 #define IC_DISTRIBUTOR_BASE_ADDR        0x00A01000
+#define L2_BASE_ADDR                    0x00A02000
 #define GPV0_BASE_ADDR                  0x00B00000
 #define GPV1_BASE_ADDR                  0x00C00000
 #define PCIE_ARB_BASE_ADDR              0x01000000