Message ID | 1348281558-19520-9-git-send-email-troy.kisky@boundarydevices.com |
---|---|
State | Changes Requested |
Headers | show |
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
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
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
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
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
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
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 >
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
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 ?
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
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
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 --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
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