[U-Boot] [PATCH 00/11] MX6: SPL NAND support

Here is a stab at adding SPL NAND support for i.MX6. I tried to take into account comments from previous attempts by others but there is still some work to be done and in particular I need some help with the issue of dealing with IMX6Q vs IMX6DL iomux in a way where the current defines can be shared by SPL as well as imximage.
Some of these can be split out of the series if needed but I wanted to post them originally as a series to provide full context.
The resulting SPL+u-boot.img has been tested on 4 different Ventana baseboards with a variety of CPU and DDR3 options.
Tim Harvey (11): SPL: NAND: remove CONFIG_SYS_NAND_PAGE_SIZE SPL: NAND: add support for mxs nand MX6: provide linker script for SPL MX6: add common SPL configuration MX6: add boot device support SPL MX6: add struct for sharing data between SPL and uboot MX6: use macro building for MX6Q/MX6DL iomux regs MX6: add mmdc configuration for MX6Q/MX6DL IMX: add additional function for pinmux using an array ventana: auto-configure for IMX6Q vs IMX6DL ventana: switch to SPL
arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 542 ++++++++++++++++++++++++++ arch/arm/cpu/armv7/mx6/soc.c | 56 +++ arch/arm/cpu/armv7/mx6/u-boot-spl.lds | 52 +++ arch/arm/imx-common/iomux-v3.c | 19 +- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 225 ++++++++++- arch/arm/include/asm/arch-mx6/mx6dl-ddr.h | 82 ++-- arch/arm/include/asm/arch-mx6/mx6q-ddr.h | 82 ++-- arch/arm/include/asm/arch-mx6/spl.h | 26 ++ arch/arm/include/asm/arch-mx6/sys_proto.h | 5 + arch/arm/include/asm/imx-common/boot_mode.h | 17 + arch/arm/include/asm/imx-common/iomux-v3.h | 5 +- board/gateworks/gw_ventana/Makefile | 2 +- board/gateworks/gw_ventana/README | 91 +++-- board/gateworks/gw_ventana/gw_ventana.c | 502 +++++++++++++++--------- board/gateworks/gw_ventana/gw_ventana.cfg | 15 - board/gateworks/gw_ventana/gw_ventana_spl.c | 394 +++++++++++++++++++ board/gateworks/gw_ventana/gw_ventana_spl.cfg | 29 ++ boards.cfg | 6 +- common/spl/spl_nand.c | 2 +- drivers/mtd/Makefile | 11 + drivers/mtd/nand/Makefile | 9 + drivers/mtd/nand/mxs_nand_spl.c | 46 +++ include/config/uboot.release | 1 + include/configs/gw_ventana.h | 13 +- include/configs/imx6_spl.h | 64 +++ spl/Makefile | 1 + 27 files changed, 1970 insertions(+), 328 deletions(-) create mode 100644 arch/arm/cpu/armv7/mx6/ddr.c create mode 100644 arch/arm/cpu/armv7/mx6/u-boot-spl.lds create mode 100644 arch/arm/include/asm/arch-mx6/spl.h create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.c create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.cfg create mode 100644 drivers/mtd/nand/mxs_nand_spl.c create mode 100644 include/config/uboot.release create mode 100644 include/configs/imx6_spl.h

We only need to read in the size of struct image_header and thus don't need to know the page size of the nand device.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- common/spl/spl_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 9da0218..062461b 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -76,7 +76,7 @@ void spl_nand_load_image(void) #endif /* Load u-boot */ nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_PAGE_SIZE, (void *)header); + sizeof(*header), (void *)header); spl_parse_image_header(header); nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, spl_image.size, (void *)spl_image.load_addr);

On Wed, 2 Apr 2014 23:01:01 -0700 Tim Harvey tharvey@gateworks.com wrote:
We only need to read in the size of struct image_header and thus don't need to know the page size of the nand device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
+1
Best Regards Masahiro Yamada

Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
We only need to read in the size of struct image_header and thus don't need to know the page size of the nand device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
common/spl/spl_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 9da0218..062461b 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -76,7 +76,7 @@ void spl_nand_load_image(void) #endif /* Load u-boot */ nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
CONFIG_SYS_NAND_PAGE_SIZE, (void *)header);
spl_parse_image_header(header); nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, spl_image.size, (void *)spl_image.load_addr);sizeof(*header), (void *)header);
+1

On 03/04/2014 08:01, Tim Harvey wrote:
We only need to read in the size of struct image_header and thus don't need to know the page size of the nand device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
common/spl/spl_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 9da0218..062461b 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -76,7 +76,7 @@ void spl_nand_load_image(void) #endif /* Load u-boot */ nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
CONFIG_SYS_NAND_PAGE_SIZE, (void *)header);
spl_parse_image_header(header); nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, spl_image.size, (void *)spl_image.load_addr);sizeof(*header), (void *)header);
Acked-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

On Mon, Apr 14, 2014 at 4:38 AM, Stefano Babic sbabic@denx.de wrote:
On 03/04/2014 08:01, Tim Harvey wrote:
We only need to read in the size of struct image_header and thus don't need to know the page size of the nand device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
common/spl/spl_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 9da0218..062461b 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -76,7 +76,7 @@ void spl_nand_load_image(void) #endif /* Load u-boot */ nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
CONFIG_SYS_NAND_PAGE_SIZE, (void *)header);
sizeof(*header), (void *)header); spl_parse_image_header(header); nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, spl_image.size, (void *)spl_image.load_addr);
Acked-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic
Scott,
This should have been addressed to you in the first place as its NAND and not IMX specific. It's been +1'd and ack'd, so if you agree with it and commit it I'll remove it from my next patch series regarding IMX6 SPL NAND support.
Tim

On Thu, 2014-04-17 at 07:18 -0700, Tim Harvey wrote:
On Mon, Apr 14, 2014 at 4:38 AM, Stefano Babic sbabic@denx.de wrote:
On 03/04/2014 08:01, Tim Harvey wrote:
We only need to read in the size of struct image_header and thus don't need to know the page size of the nand device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
common/spl/spl_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 9da0218..062461b 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -76,7 +76,7 @@ void spl_nand_load_image(void) #endif /* Load u-boot */ nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS,
CONFIG_SYS_NAND_PAGE_SIZE, (void *)header);
sizeof(*header), (void *)header); spl_parse_image_header(header); nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, spl_image.size, (void *)spl_image.load_addr);
Acked-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic
Scott,
This should have been addressed to you in the first place as its NAND and not IMX specific. It's been +1'd and ack'd, so if you agree with it and commit it I'll remove it from my next patch series regarding IMX6 SPL NAND support.
I suppose it's not worse than what's already there, but I really don't like the way nand_spl_load_image takes a pointer and a size, but can write more bytes to the pointer than the size that was given (it rounds up to the block -- not page -- size).
That said, Acked-by: Scott Wood scottwood@freescale.com ...and feel free to leave it in with the rest of the patchset.
-Scott

This utilizes existing nand support, including the mtd layer to provide a a method to load an image off nand for SPL. It is somewhat bulky but avoids duplicating code.
This will need to be split out and re-based on top of Tom's recent patch to add MTD NAND support which is needed here.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- drivers/mtd/Makefile | 11 ++++++++++ drivers/mtd/nand/Makefile | 9 ++++++++ drivers/mtd/nand/mxs_nand_spl.c | 46 +++++++++++++++++++++++++++++++++++++++++ spl/Makefile | 1 + 4 files changed, 67 insertions(+) create mode 100644 drivers/mtd/nand/mxs_nand_spl.c
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 5467a95..10ec470 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -5,6 +5,15 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifdef CONFIG_SPL_BUILD + +ifdef CONFIG_SPL_NAND_MXS +obj-y += mtdcore.o +obj-y += mtdpart.o +endif + +else # not spl + ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND))) obj-y += mtdcore.o endif @@ -18,3 +27,5 @@ obj-$(CONFIG_FTSMC020) += ftsmc020.o obj-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o obj-$(CONFIG_ST_SMI) += st_smi.o + +endif diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 02b149c..8b1a37a 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -19,6 +19,14 @@ obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o obj-$(CONFIG_SPL_NAND_INIT) += nand.o
+ifdef CONFIG_SPL_NAND_MXS +obj-y += mxs_nand_spl.o +obj-y += nand_bbt.o +obj-y += nand_ids.o +obj-y += nand_util.o +obj-y += nand_ecc.o +endif + else # not spl
NORMAL_DRIVERS=y @@ -65,5 +73,6 @@ else # minimal SPL drivers obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o +obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
endif # drivers diff --git a/drivers/mtd/nand/mxs_nand_spl.c b/drivers/mtd/nand/mxs_nand_spl.c new file mode 100644 index 0000000..ec07eb1 --- /dev/null +++ b/drivers/mtd/nand/mxs_nand_spl.c @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2014 + * Tim Harvey, Gateworks Corporation, tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <nand.h> + +static nand_info_t mtd; +static struct nand_chip nand_chip; + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{ + size_t sz, actual; + + debug("%s offset:0x%08x len:%d\n", __func__, offs, size); + sz = size; + nand_read_skip_bad(&mtd, (loff_t) offs, &sz, &actual, size, dst); + debug("read %d/%d bytes\n", sz, actual); + + return 0; +} + +void nand_init(void) +{ + int ret; + + board_nand_init(&nand_chip); + mtd.priv = &nand_chip; + if (nand_chip.select_chip) + nand_chip.select_chip(&mtd, 0); + + ret = nand_scan(&mtd, 1); + if (!ret) + ret = nand_scan_tail(&mtd); + debug("oobsize=%d pagesize=%d\n", mtd.oobsize, mtd.writesize); + printf("NAND: %llu MiB\n", (mtd.size / (1024 * 1024))); +} + +void nand_deselect(void) +{ + if (nand_chip.select_chip) + nand_chip.select_chip(&mtd, -1); +} diff --git a/spl/Makefile b/spl/Makefile index 346d0aa..6a2c80f 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -103,6 +103,7 @@ libs-y += fs/ libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/ libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/ drivers/power/pmic/ libs-$(if $(CONFIG_CMD_NAND),$(CONFIG_SPL_NAND_SUPPORT)) += drivers/mtd/nand/ +libs-$(CONFIG_SPL_NAND_MXS) += drivers/mtd/ libs-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += drivers/misc/ libs-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/ libs-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/

Hi Tim,
sorry for late review.
On 03/04/2014 08:01, Tim Harvey wrote:
This utilizes existing nand support, including the mtd layer to provide a a method to load an image off nand for SPL. It is somewhat bulky but avoids duplicating code.
This will need to be split out and re-based on top of Tom's recent patch to add MTD NAND support which is needed here.
Signed-off-by: Tim Harvey tharvey@gateworks.com
drivers/mtd/Makefile | 11 ++++++++++ drivers/mtd/nand/Makefile | 9 ++++++++ drivers/mtd/nand/mxs_nand_spl.c | 46 +++++++++++++++++++++++++++++++++++++++++ spl/Makefile | 1 + 4 files changed, 67 insertions(+) create mode 100644 drivers/mtd/nand/mxs_nand_spl.c
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 5467a95..10ec470 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -5,6 +5,15 @@ # SPDX-License-Identifier: GPL-2.0+ #
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_SPL_NAND_MXS +obj-y += mtdcore.o +obj-y += mtdpart.o +endif
This is usually:
obj-$(CONFIG_SPL_NAND_MXS) += mtdcore.o mtdpart.o
+else # not spl
ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND))) obj-y += mtdcore.o endif @@ -18,3 +27,5 @@ obj-$(CONFIG_FTSMC020) += ftsmc020.o obj-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o obj-$(CONFIG_ST_SMI) += st_smi.o
+endif diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 02b149c..8b1a37a 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -19,6 +19,14 @@ obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o obj-$(CONFIG_SPL_NAND_INIT) += nand.o
+ifdef CONFIG_SPL_NAND_MXS +obj-y += mxs_nand_spl.o +obj-y += nand_bbt.o +obj-y += nand_ids.o +obj-y += nand_util.o +obj-y += nand_ecc.o +endif
Ditto.
else # not spl
NORMAL_DRIVERS=y @@ -65,5 +73,6 @@ else # minimal SPL drivers obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o +obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o
endif # drivers diff --git a/drivers/mtd/nand/mxs_nand_spl.c b/drivers/mtd/nand/mxs_nand_spl.c new file mode 100644 index 0000000..ec07eb1 --- /dev/null +++ b/drivers/mtd/nand/mxs_nand_spl.c @@ -0,0 +1,46 @@ +/*
- (C) Copyright 2014
- Tim Harvey, Gateworks Corporation, tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <nand.h>
+static nand_info_t mtd; +static struct nand_chip nand_chip;
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{
- size_t sz, actual;
- debug("%s offset:0x%08x len:%d\n", __func__, offs, size);
- sz = size;
- nand_read_skip_bad(&mtd, (loff_t) offs, &sz, &actual, size, dst);
- debug("read %d/%d bytes\n", sz, actual);
- return 0;
+}
+void nand_init(void) +{
- int ret;
- board_nand_init(&nand_chip);
- mtd.priv = &nand_chip;
- if (nand_chip.select_chip)
nand_chip.select_chip(&mtd, 0);
- ret = nand_scan(&mtd, 1);
- if (!ret)
ret = nand_scan_tail(&mtd);
- debug("oobsize=%d pagesize=%d\n", mtd.oobsize, mtd.writesize);
- printf("NAND: %llu MiB\n", (mtd.size / (1024 * 1024)));
+}
+void nand_deselect(void) +{
- if (nand_chip.select_chip)
nand_chip.select_chip(&mtd, -1);
+} diff --git a/spl/Makefile b/spl/Makefile index 346d0aa..6a2c80f 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -103,6 +103,7 @@ libs-y += fs/ libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/ libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/ drivers/power/pmic/ libs-$(if $(CONFIG_CMD_NAND),$(CONFIG_SPL_NAND_SUPPORT)) += drivers/mtd/nand/ +libs-$(CONFIG_SPL_NAND_MXS) += drivers/mtd/ libs-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += drivers/misc/ libs-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/ libs-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/
The main issue (I read also Scott's answer for Patch 4/11) is due to the fact that you link a lot of MTD code, increasing the footprint. This becomes an exception, because only a restricted number of function were introduces for other SOCs (see mxc_nand_spl.c or code in omap_gpmc.c). Sure that we cannot get rid of it ?
Best regards, Stefano Babic

Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/armv7/mx6/u-boot-spl.lds | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 arch/arm/cpu/armv7/mx6/u-boot-spl.lds
diff --git a/arch/arm/cpu/armv7/mx6/u-boot-spl.lds b/arch/arm/cpu/armv7/mx6/u-boot-spl.lds new file mode 100644 index 0000000..02aa129 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/u-boot-spl.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, garyj@denx.de + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * Aneesh V aneesh@ti.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\ + LENGTH = CONFIG_SPL_MAX_SIZE } +MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \ + LENGTH = CONFIG_SPL_BSS_MAX_SIZE } + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + .text : + { + __start = .; + arch/arm/cpu/armv7/start.o (.text*) + *(.text*) + } >.sram + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram + + . = ALIGN(4); + .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*_i2c_*))); + } >.sram + + . = ALIGN(4); + __image_copy_end = .; + _end = .; + + .bss : + { + . = ALIGN(4); + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } >.sdram +}

Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/cpu/armv7/mx6/u-boot-spl.lds | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 arch/arm/cpu/armv7/mx6/u-boot-spl.lds
+1

Hi Tim,
On 03/04/2014 08:01, Tim Harvey wrote:
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/cpu/armv7/mx6/u-boot-spl.lds | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 arch/arm/cpu/armv7/mx6/u-boot-spl.lds
diff --git a/arch/arm/cpu/armv7/mx6/u-boot-spl.lds b/arch/arm/cpu/armv7/mx6/u-boot-spl.lds new file mode 100644 index 0000000..02aa129 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/u-boot-spl.lds @@ -0,0 +1,52 @@ +/*
- (C) Copyright 2002
- Gary Jennejohn, DENX Software Engineering, garyj@denx.de
- (C) Copyright 2010
- Texas Instruments, <www.ti.com>
- Aneesh V aneesh@ti.com
- SPDX-License-Identifier: GPL-2.0+
- */
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{
- .text :
- {
__start = .;
arch/arm/cpu/armv7/start.o (.text*)
*(.text*)
- } >.sram
- . = ALIGN(4);
- .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
- . = ALIGN(4);
- .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
- . = ALIGN(4);
- .u_boot_list : {
KEEP(*(SORT(.u_boot_list*_i2c_*)));
- } >.sram
- . = ALIGN(4);
- __image_copy_end = .;
- _end = .;
- .bss :
- {
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end = .;
- } >.sdram
+}
This file is pretty identical to ./arch/arm/cpu/armv7/omap-common/u-boot-spl.lds. I understand that each SOC/arch could be a different set up, but I think we should introduce this diversity when it is needed, not as default.
Maybe can we avoid to copy the file ?
Best regards, Stefano Babic

On Mon, Apr 14, 2014 at 5:02 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
<snip>
This file is pretty identical to ./arch/arm/cpu/armv7/omap-common/u-boot-spl.lds. I understand that each SOC/arch could be a different set up, but I think we should introduce this diversity when it is needed, not as default.
Maybe can we avoid to copy the file ?
Stefano,
Yes, I agree - the omap-common file will work for imx6 as well. I will use it and remove this patch.
Regards,
Tim

On Thu, Apr 17, 2014 at 3:27 AM, Tim Harvey tharvey@gateworks.com wrote:
On Mon, Apr 14, 2014 at 5:02 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
<snip> > This file is pretty identical to > ./arch/arm/cpu/armv7/omap-common/u-boot-spl.lds. I understand that each > SOC/arch could be a different set up, but I think we should introduce > this diversity when it is needed, not as default. > > Maybe can we avoid to copy the file ? >
Stefano,
Yes, I agree - the omap-common file will work for imx6 as well. I will use it and remove this patch.
So it'd be better to move to spl-common dir?

Add a common header which can hopefully be shared among imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com --- include/configs/imx6_spl.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 include/configs/imx6_spl.h
diff --git a/include/configs/imx6_spl.h b/include/configs/imx6_spl.h new file mode 100644 index 0000000..f9bdf55 --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,64 @@ +/* + * Author: Tim Harvey tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __IMX6_SPL_CONFIG_H +#define __IMX6_SPL_CONFIG_H + +#ifdef CONFIG_SPL + +#define CONFIG_SPL_FRAMEWORK + +/* + * IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0093FFFF + * - we start at 0x00908000 so as to leave some room for IVT/DCD + * - recommended stack (from IMX6DQRM Figure 8-3) is at 0x0093FFB8 + * - this leaves about 224K for SPL image and stack + */ +#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/mx6/u-boot-spl.lds" +#define CONFIG_SPL_TEXT_BASE 0x00908000 +#define CONFIG_SPL_MAX_SIZE (128 * 1024) +#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7" +#define CONFIG_SPL_STACK 0x0093FFB8 +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SPL_GPIO_SUPPORT + +/* NAND support */ +#if defined(CONFIG_SPL_NAND_SUPPORT) +#define CONFIG_SPL_NAND_MXS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_DMA_SUPPORT +#endif + +/* MMC support */ +#if defined(CONFIG_SPL_MMC_SUPPORT) +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 138 /* offset 69KB */ +#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS 800 /* 400 KB */ +#define CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION 1 +#define CONFIG_SYS_MONITOR_LEN (CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS/2*1024) +#endif + +/* SATA support */ +#if defined(CONFIG_SPL_SATA_SUPPORT) +#define CONFIG_SPL_SATA_BOOT_DEVICE 0 +#define CONFIG_SYS_SATA_FAT_BOOT_PARTITION 1 +#endif + +/* Define the payload for FAT/EXT support */ +#if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT) +#define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img" +#define CONFIG_SPL_LIBDISK_SUPPORT +#endif + +#define CONFIG_SPL_BSS_START_ADDR 0x18200000 +#define CONFIG_SPL_BSS_MAX_SIZE 0x100000 /* 1 MB */ +#define CONFIG_SYS_SPL_MALLOC_START 0x18300000 +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x3200000 /* 50 MB */ +#define CONFIG_SYS_TEXT_BASE 0x17800000 +#endif + +#endif

Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:> Add a common header which can hopefully be shared among imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
include/configs/imx6_spl.h | 64
++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+) create mode 100644 include/configs/imx6_spl.h
diff --git a/include/configs/imx6_spl.h b/include/configs/imx6_spl.h new file mode 100644 index 0000000..f9bdf55 --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,64 @@ +/*
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __IMX6_SPL_CONFIG_H +#define __IMX6_SPL_CONFIG_H
+#ifdef CONFIG_SPL
+#define CONFIG_SPL_FRAMEWORK
+/*
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0093FFFF
That's not true for all IMX6 SoCs. On i.MX6 Solo and DualLite it's 0x00907000 to 0x0091FFFF.
- we start at 0x00908000 so as to leave some room for IVT/DCD
- recommended stack (from IMX6DQRM Figure 8-3) is at 0x0093FFB8
- this leaves about 224K for SPL image and stack
- */
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/mx6/u-boot-spl.lds" +#define CONFIG_SPL_TEXT_BASE 0x00908000 +#define CONFIG_SPL_MAX_SIZE (128 * 1024)
This should be a smaller value if we want this config to apply for i.MX6 Solo and DualLite, which have a 68KB OCRAM free area.
+#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7" +#define CONFIG_SPL_STACK 0x0093FFB8
For i.MX6 Solo and DualLite this address should be lower (recommended address is 0x0091FFB8).
+#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SPL_GPIO_SUPPORT
+/* NAND support */ +#if defined(CONFIG_SPL_NAND_SUPPORT) +#define CONFIG_SPL_NAND_MXS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_DMA_SUPPORT +#endif

On Wed, Apr 9, 2014 at 7:55 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:> Add a common header which can hopefully be shared among imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
include/configs/imx6_spl.h | 64
++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+) create mode 100644 include/configs/imx6_spl.h
diff --git a/include/configs/imx6_spl.h b/include/configs/imx6_spl.h new file mode 100644 index 0000000..f9bdf55 --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,64 @@ +/*
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __IMX6_SPL_CONFIG_H +#define __IMX6_SPL_CONFIG_H
+#ifdef CONFIG_SPL
+#define CONFIG_SPL_FRAMEWORK
+/*
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0093FFFF
That's not true for all IMX6 SoCs. On i.MX6 Solo and DualLite it's 0x00907000 to 0x0091FFFF.
- we start at 0x00908000 so as to leave some room for IVT/DCD
- recommended stack (from IMX6DQRM Figure 8-3) is at 0x0093FFB8
- this leaves about 224K for SPL image and stack
- */
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/mx6/u-boot-spl.lds" +#define CONFIG_SPL_TEXT_BASE 0x00908000 +#define CONFIG_SPL_MAX_SIZE (128 * 1024)
This should be a smaller value if we want this config to apply for i.MX6 Solo and DualLite, which have a 68KB OCRAM free area.
Hi Nikita,
Agreed - I just discovered this yesterday. I had tested on an IMX6DL/SOLO via boot from OTG, but I had not tested those combinations when booting from flash and indeed they failed.
The 68KB OCRAM free area also assumes that you start at 0x00907000 and as we start at 0x00908000 to leave room for the IVT+DCD this becomes 65KB
+#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7" +#define CONFIG_SPL_STACK 0x0093FFB8
For i.MX6 Solo and DualLite this address should be lower (recommended address is 0x0091FFB8).
Agreed
+#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SPL_GPIO_SUPPORT
+/* NAND support */ +#if defined(CONFIG_SPL_NAND_SUPPORT) +#define CONFIG_SPL_NAND_MXS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_DMA_SUPPORT +#endif
-- Regards, Nikita.
This presents another challenge for SPL NAND as currently my SPL is ~70K. There is a lot of unnecessary code in the mtd nand layer that I'm including because that layer includes support for both read and write (I don't need write for SPL) as well as various NAND types (and I only need BCH).
I'm not sure yet what the best approach is to resolve that. I can either: a) add a lot of ifdef's around functions in drivers/mtd/nand/{nand_base.c,nand_bbt.c} to remove NAND write and non BCH support for CONFIG_SPL_BUILD b) re-write the necessary functionality (code duplication) into drivers/mtd/nand/mxs_nand_spl.c
Thanks for the review!
Tim

On 04/09/2014 06:32 PM, Tim Harvey wrote:
On Wed, Apr 9, 2014 at 7:55 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:> Add a common header which can hopefully be shared among imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
include/configs/imx6_spl.h | 64
++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+) create mode 100644 include/configs/imx6_spl.h
diff --git a/include/configs/imx6_spl.h b/include/configs/imx6_spl.h new file mode 100644 index 0000000..f9bdf55 --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,64 @@ +/*
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __IMX6_SPL_CONFIG_H +#define __IMX6_SPL_CONFIG_H
+#ifdef CONFIG_SPL
+#define CONFIG_SPL_FRAMEWORK
+/*
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0093FFFF
That's not true for all IMX6 SoCs. On i.MX6 Solo and DualLite it's 0x00907000 to 0x0091FFFF.
- we start at 0x00908000 so as to leave some room for IVT/DCD
- recommended stack (from IMX6DQRM Figure 8-3) is at 0x0093FFB8
- this leaves about 224K for SPL image and stack
- */
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/mx6/u-boot-spl.lds" +#define CONFIG_SPL_TEXT_BASE 0x00908000 +#define CONFIG_SPL_MAX_SIZE (128 * 1024)
This should be a smaller value if we want this config to apply for i.MX6 Solo and DualLite, which have a 68KB OCRAM free area.
Hi Nikita,
Agreed - I just discovered this yesterday. I had tested on an IMX6DL/SOLO via boot from OTG, but I had not tested those combinations when booting from flash and indeed they failed.
The 68KB OCRAM free area also assumes that you start at 0x00907000 and as we start at 0x00908000 to leave room for the IVT+DCD this becomes 65KB
+#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7" +#define CONFIG_SPL_STACK 0x0093FFB8
For i.MX6 Solo and DualLite this address should be lower (recommended address is 0x0091FFB8).
Agreed
+#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SPL_GPIO_SUPPORT
+/* NAND support */ +#if defined(CONFIG_SPL_NAND_SUPPORT) +#define CONFIG_SPL_NAND_MXS +#define CONFIG_SPL_NAND_BASE +#define CONFIG_SPL_DMA_SUPPORT +#endif
-- Regards, Nikita.
This presents another challenge for SPL NAND as currently my SPL is ~70K. There is a lot of unnecessary code in the mtd nand layer that I'm including because that layer includes support for both read and write (I don't need write for SPL) as well as various NAND types (and I only need BCH).
I'm not sure yet what the best approach is to resolve that. I can either: a) add a lot of ifdef's around functions in drivers/mtd/nand/{nand_base.c,nand_bbt.c} to remove NAND write and non BCH support for CONFIG_SPL_BUILD b) re-write the necessary functionality (code duplication) into drivers/mtd/nand/mxs_nand_spl.c
Thanks for the review!
You're welcome. Let's see if the NAND maintainer can offer some suggestions.
Cc-ing Scott Wood
Tim

On Thu, 2014-04-10 at 17:37 +0300, Nikita Kiryanov wrote:
On 04/09/2014 06:32 PM, Tim Harvey wrote:
This presents another challenge for SPL NAND as currently my SPL is ~70K. There is a lot of unnecessary code in the mtd nand layer that I'm including because that layer includes support for both read and write (I don't need write for SPL) as well as various NAND types (and I only need BCH).
I'm not sure yet what the best approach is to resolve that. I can either: a) add a lot of ifdef's around functions in drivers/mtd/nand/{nand_base.c,nand_bbt.c} to remove NAND write and non BCH support for CONFIG_SPL_BUILD b) re-write the necessary functionality (code duplication) into drivers/mtd/nand/mxs_nand_spl.c
Thanks for the review!
You're welcome. Let's see if the NAND maintainer can offer some suggestions.
Cc-ing Scott Wood
While I certainly wouldn't mind someone putting in the effort to slim down the main NAND code, so far we've followed option b when we need a tiny NAND SPL.
-Scott

Add enums, #defines, and helper functions needed for SPL images to describe and detect IMX6 boot device.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/armv7/mx6/soc.c | 56 +++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/spl.h | 26 ++++++++++++++ arch/arm/include/asm/imx-common/boot_mode.h | 17 +++++++++ 3 files changed, 99 insertions(+) create mode 100644 arch/arm/include/asm/arch-mx6/spl.h
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 1725279..4ee62c7 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -305,6 +305,62 @@ const struct boot_mode soc_boot_modes[] = { {NULL, 0}, };
+/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +enum boot_device get_boot_device(void) +{ + enum boot_device boot_dev; + + uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4); /* SRC_SBMR1 */ + + /* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */ + switch ((soc_sbmr & 0x000000FF) >> 4) { + /* EIM: See 8.5.1, Table 8-9 */ + case 0x0: + /* BOOT_CFG1[3]: NOR/OneNAND Selection */ + if ((soc_sbmr & 0x00000008) >> 3) + boot_dev = MX6_ONE_NAND_BOOT; + else + boot_dev = MX6_WEIM_NOR_BOOT; + break; + /* SATA: See 8.5.4, Table 8-20 */ + case 0x2: + boot_dev = MX6_SATA_BOOT; + break; + /* Serial ROM: See 8.5.5.1, Table 8-22 */ + case 0x3: + /* BOOT_CFG4[2:0] */ + switch ((soc_sbmr & 0x07000000) >> 24) { + case 0x0 ... 0x4: + boot_dev = MX6_SPI_NOR_BOOT; + break; + case 0x5 ... 0x7: + boot_dev = MX6_I2C_BOOT; + break; + } + break; + /* SD/eSD: 8.5.3, Table 8-15 */ + case 0x4: + case 0x5: + boot_dev = MX6_SD_BOOT; + break; + /* MMC/eMMC: 8.5.3 */ + case 0x6: + case 0x7: + boot_dev = MX6_MMC_BOOT; + break; + /* NAND Flash: 8.5.2 */ + case 0x8 ... 0xf: + boot_dev = MX6_NAND_BOOT; + break; + default: + boot_dev = MX6_UNKNOWN_BOOT; + break; + } + + return boot_dev; +} + + void s_init(void) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; diff --git a/arch/arm/include/asm/arch-mx6/spl.h b/arch/arm/include/asm/arch-mx6/spl.h new file mode 100644 index 0000000..5611c71 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/spl.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 TechNexion Ltd. + * + * Author: Richard Hu linuxfae@technexion.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef __ASM_ARCH_SPL_H__ +#define __ASM_ARCH_SPL_H__ + +#define BOOT_DEVICE_MMC1 0 +#define BOOT_DEVICE_MMC2 1 +#define BOOT_DEVICE_MMC2_2 2 +#define BOOT_DEVICE_NAND 3 +#define BOOT_DEVICE_SATA 4 +#define BOOT_DEVICE_USBETH 5 +#define BOOT_DEVICE_NONE 6 + +#endif /* __ASM_ARCH_SPL_H__ */ diff --git a/arch/arm/include/asm/imx-common/boot_mode.h b/arch/arm/include/asm/imx-common/boot_mode.h index de0205c..3686367 100644 --- a/arch/arm/include/asm/imx-common/boot_mode.h +++ b/arch/arm/include/asm/imx-common/boot_mode.h @@ -17,4 +17,21 @@ struct boot_mode { void add_board_boot_modes(const struct boot_mode *p); void boot_mode_apply(unsigned cfg_val); extern const struct boot_mode soc_boot_modes[]; + +/* boot devices */ +enum boot_device { + MX6_SD_BOOT, + MX6_MMC_BOOT, + MX6_NAND_BOOT, + MX6_SATA_BOOT, + MX6_WEIM_NOR_BOOT, + MX6_ONE_NAND_BOOT, + MX6_PATA_BOOT, + MX6_I2C_BOOT, + MX6_SPI_NOR_BOOT, + MX6_UNKNOWN_BOOT, + MX6_BOOT_DEV_NUM = MX6_UNKNOWN_BOOT, +}; +enum boot_device get_boot_device(void); + #endif

Hi Tim,
On 03/04/2014 08:01, Tim Harvey wrote:
Add enums, #defines, and helper functions needed for SPL images to describe and detect IMX6 boot device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/cpu/armv7/mx6/soc.c | 56 +++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/spl.h | 26 ++++++++++++++ arch/arm/include/asm/imx-common/boot_mode.h | 17 +++++++++ 3 files changed, 99 insertions(+) create mode 100644 arch/arm/include/asm/arch-mx6/spl.h
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 1725279..4ee62c7 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -305,6 +305,62 @@ const struct boot_mode soc_boot_modes[] = { {NULL, 0}, };
+/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +enum boot_device get_boot_device(void) +{
- enum boot_device boot_dev;
- uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4); /* SRC_SBMR1 */
Use structure to access internal registers. The structure is already defined in imx-regs.h.
- /* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
- switch ((soc_sbmr & 0x000000FF) >> 4) {
/* EIM: See 8.5.1, Table 8-9 */
- case 0x0:
/* BOOT_CFG1[3]: NOR/OneNAND Selection */
if ((soc_sbmr & 0x00000008) >> 3)
boot_dev = MX6_ONE_NAND_BOOT;
else
boot_dev = MX6_WEIM_NOR_BOOT;
break;
- /* SATA: See 8.5.4, Table 8-20 */
- case 0x2:
Can we use #defines for that ?
boot_dev = MX6_SATA_BOOT;
break;
- /* Serial ROM: See 8.5.5.1, Table 8-22 */
- case 0x3:
/* BOOT_CFG4[2:0] */
switch ((soc_sbmr & 0x07000000) >> 24) {
case 0x0 ... 0x4:
boot_dev = MX6_SPI_NOR_BOOT;
break;
case 0x5 ... 0x7:
boot_dev = MX6_I2C_BOOT;
break;
}
break;
- /* SD/eSD: 8.5.3, Table 8-15 */
- case 0x4:
- case 0x5:
boot_dev = MX6_SD_BOOT;
break;
- /* MMC/eMMC: 8.5.3 */
- case 0x6:
- case 0x7:
boot_dev = MX6_MMC_BOOT;
break;
- /* NAND Flash: 8.5.2 */
- case 0x8 ... 0xf:
boot_dev = MX6_NAND_BOOT;
break;
- default:
boot_dev = MX6_UNKNOWN_BOOT;
break;
- }
The function can be used as well for MX5 SOCs. Move it into imx-common, and use constants without SOC names. Instead of MX6_NAND_BOOT, IMX_NAND_BOOT (or whatever you find makes sense..)
- return boot_dev;
+}
void s_init(void) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; diff --git a/arch/arm/include/asm/arch-mx6/spl.h b/arch/arm/include/asm/arch-mx6/spl.h new file mode 100644 index 0000000..5611c71 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/spl.h @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2013 TechNexion Ltd.
- Author: Richard Hu linuxfae@technexion.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- */
+#ifndef __ASM_ARCH_SPL_H__ +#define __ASM_ARCH_SPL_H__
+#define BOOT_DEVICE_MMC1 0 +#define BOOT_DEVICE_MMC2 1 +#define BOOT_DEVICE_MMC2_2 2 +#define BOOT_DEVICE_NAND 3 +#define BOOT_DEVICE_SATA 4 +#define BOOT_DEVICE_USBETH 5 +#define BOOT_DEVICE_NONE 6
They are only defines and are not yet related to i.MX6 anymnore, because you have already mapped them. What about to move this defines into imx-common ?
+#endif /* __ASM_ARCH_SPL_H__ */ diff --git a/arch/arm/include/asm/imx-common/boot_mode.h b/arch/arm/include/asm/imx-common/boot_mode.h index de0205c..3686367 100644 --- a/arch/arm/include/asm/imx-common/boot_mode.h +++ b/arch/arm/include/asm/imx-common/boot_mode.h @@ -17,4 +17,21 @@ struct boot_mode { void add_board_boot_modes(const struct boot_mode *p); void boot_mode_apply(unsigned cfg_val); extern const struct boot_mode soc_boot_modes[];
+/* boot devices */ +enum boot_device {
- MX6_SD_BOOT,
- MX6_MMC_BOOT,
- MX6_NAND_BOOT,
- MX6_SATA_BOOT,
- MX6_WEIM_NOR_BOOT,
- MX6_ONE_NAND_BOOT,
- MX6_PATA_BOOT,
- MX6_I2C_BOOT,
- MX6_SPI_NOR_BOOT,
- MX6_UNKNOWN_BOOT,
- MX6_BOOT_DEV_NUM = MX6_UNKNOWN_BOOT,
+};
See my remark before.
+enum boot_device get_boot_device(void);
#endif
Best regards, Stefano Babic

On Mon, Apr 14, 2014 at 5:27 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 1725279..4ee62c7 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -305,6 +305,62 @@ const struct boot_mode soc_boot_modes[] = { {NULL, 0}, };
+/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +enum boot_device get_boot_device(void) +{
enum boot_device boot_dev;
uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4); /* SRC_SBMR1 */
Use structure to access internal registers. The structure is already defined in imx-regs.h.
Agreed - I will do this for v2.
/* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
switch ((soc_sbmr & 0x000000FF) >> 4) {
/* EIM: See 8.5.1, Table 8-9 */
case 0x0:
/* BOOT_CFG1[3]: NOR/OneNAND Selection */
if ((soc_sbmr & 0x00000008) >> 3)
boot_dev = MX6_ONE_NAND_BOOT;
else
boot_dev = MX6_WEIM_NOR_BOOT;
break;
/* SATA: See 8.5.4, Table 8-20 */
case 0x2:
Can we use #defines for that ?
Yes, I'll add them to imx-regs.h.
boot_dev = MX6_SATA_BOOT;
break;
/* Serial ROM: See 8.5.5.1, Table 8-22 */
case 0x3:
/* BOOT_CFG4[2:0] */
switch ((soc_sbmr & 0x07000000) >> 24) {
case 0x0 ... 0x4:
boot_dev = MX6_SPI_NOR_BOOT;
break;
case 0x5 ... 0x7:
boot_dev = MX6_I2C_BOOT;
break;
}
break;
/* SD/eSD: 8.5.3, Table 8-15 */
case 0x4:
case 0x5:
boot_dev = MX6_SD_BOOT;
break;
/* MMC/eMMC: 8.5.3 */
case 0x6:
case 0x7:
boot_dev = MX6_MMC_BOOT;
break;
/* NAND Flash: 8.5.2 */
case 0x8 ... 0xf:
boot_dev = MX6_NAND_BOOT;
break;
default:
boot_dev = MX6_UNKNOWN_BOOT;
break;
}
The function can be used as well for MX5 SOCs. Move it into imx-common, and use constants without SOC names. Instead of MX6_NAND_BOOT, IMX_NAND_BOOT (or whatever you find makes sense..)
Are you saying the i.MX5's have the same register and meaning? I figured the sbmr is different.
return boot_dev;
+}
void s_init(void) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; diff --git a/arch/arm/include/asm/arch-mx6/spl.h b/arch/arm/include/asm/arch-mx6/spl.h new file mode 100644 index 0000000..5611c71 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/spl.h @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2013 TechNexion Ltd.
- Author: Richard Hu linuxfae@technexion.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- */
+#ifndef __ASM_ARCH_SPL_H__ +#define __ASM_ARCH_SPL_H__
+#define BOOT_DEVICE_MMC1 0 +#define BOOT_DEVICE_MMC2 1 +#define BOOT_DEVICE_MMC2_2 2 +#define BOOT_DEVICE_NAND 3 +#define BOOT_DEVICE_SATA 4 +#define BOOT_DEVICE_USBETH 5 +#define BOOT_DEVICE_NONE 6
They are only defines and are not yet related to i.MX6 anymnore, because you have already mapped them. What about to move this defines into imx-common ?
ok
+#endif /* __ASM_ARCH_SPL_H__ */ diff --git a/arch/arm/include/asm/imx-common/boot_mode.h b/arch/arm/include/asm/imx-common/boot_mode.h index de0205c..3686367 100644 --- a/arch/arm/include/asm/imx-common/boot_mode.h +++ b/arch/arm/include/asm/imx-common/boot_mode.h @@ -17,4 +17,21 @@ struct boot_mode { void add_board_boot_modes(const struct boot_mode *p); void boot_mode_apply(unsigned cfg_val); extern const struct boot_mode soc_boot_modes[];
+/* boot devices */ +enum boot_device {
MX6_SD_BOOT,
MX6_MMC_BOOT,
MX6_NAND_BOOT,
MX6_SATA_BOOT,
MX6_WEIM_NOR_BOOT,
MX6_ONE_NAND_BOOT,
MX6_PATA_BOOT,
MX6_I2C_BOOT,
MX6_SPI_NOR_BOOT,
MX6_UNKNOWN_BOOT,
MX6_BOOT_DEV_NUM = MX6_UNKNOWN_BOOT,
+};
See my remark before.
ok
I hope to have a v2 posted soon.
Regards,
Tim
+enum boot_device get_boot_device(void);
#endif

Hi Tim,
On 17/04/2014 08:16, Tim Harvey wrote:
boot_dev = MX6_SATA_BOOT;
break;
/* Serial ROM: See 8.5.5.1, Table 8-22 */
case 0x3:
/* BOOT_CFG4[2:0] */
switch ((soc_sbmr & 0x07000000) >> 24) {
case 0x0 ... 0x4:
boot_dev = MX6_SPI_NOR_BOOT;
break;
case 0x5 ... 0x7:
boot_dev = MX6_I2C_BOOT;
break;
}
break;
/* SD/eSD: 8.5.3, Table 8-15 */
case 0x4:
case 0x5:
boot_dev = MX6_SD_BOOT;
break;
/* MMC/eMMC: 8.5.3 */
case 0x6:
case 0x7:
boot_dev = MX6_MMC_BOOT;
break;
/* NAND Flash: 8.5.2 */
case 0x8 ... 0xf:
boot_dev = MX6_NAND_BOOT;
break;
default:
boot_dev = MX6_UNKNOWN_BOOT;
break;
}
The function can be used as well for MX5 SOCs. Move it into imx-common, and use constants without SOC names. Instead of MX6_NAND_BOOT, IMX_NAND_BOOT (or whatever you find makes sense..)
Are you saying the i.MX5's have the same register and meaning? I figured the sbmr is different.
The register is the same, and mostly with the same meaning. You do not need to care about it. Just put it into imx-common, and when someone will add support for MX5, this function will be analyzed and modified instead of adding a new one.
return boot_dev;
+}
void s_init(void) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; diff --git a/arch/arm/include/asm/arch-mx6/spl.h b/arch/arm/include/asm/arch-mx6/spl.h new file mode 100644 index 0000000..5611c71 --- /dev/null +++ b/arch/arm/include/asm/arch-mx6/spl.h @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2013 TechNexion Ltd.
- Author: Richard Hu linuxfae@technexion.com
- See file CREDITS for list of people who contributed to this
- project.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
- */
+#ifndef __ASM_ARCH_SPL_H__ +#define __ASM_ARCH_SPL_H__
+#define BOOT_DEVICE_MMC1 0 +#define BOOT_DEVICE_MMC2 1 +#define BOOT_DEVICE_MMC2_2 2 +#define BOOT_DEVICE_NAND 3 +#define BOOT_DEVICE_SATA 4 +#define BOOT_DEVICE_USBETH 5 +#define BOOT_DEVICE_NONE 6
They are only defines and are not yet related to i.MX6 anymnore, because you have already mapped them. What about to move this defines into imx-common ?
ok
Masahiro has sent this week a patch to consolidate names, that are duplicated for all architecture: http://patchwork.ozlabs.org/patch/339438/
I think it is a very good idea to follow his approach.
I hope to have a v2 posted soon.
Please only wait until I send my remark regarding the patches with pinmux.
Best regards, Stefano Babic

This can be used to pass info between the SPL and u-boot.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/include/asm/arch-mx6/sys_proto.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 38851a1..f43e09c 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -39,4 +39,9 @@ int mxs_wait_mask_set(struct mxs_register_32 *reg, int mxs_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned int timeout); + +struct mx6_spl_data { + uint8_t boot_mode_idx; + uint32_t mem_dram_size; +}; #endif

Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
This can be used to pass info between the SPL and u-boot.
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/include/asm/arch-mx6/sys_proto.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 38851a1..f43e09c 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -39,4 +39,9 @@ int mxs_wait_mask_set(struct mxs_register_32 *reg, int mxs_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned int timeout);
+struct mx6_spl_data {
- uint8_t boot_mode_idx;
- uint32_t mem_dram_size;
+}; #endif
While I'm in favor of having some way for SPL to pass data to U-Boot, I don't think this patch achieves this as long as we don't have a common mechanism that makes use of this struct. At the very least I would've expected to see a #define that is shared by SPL and U-Boot that defines the address for this struct (if we were to use the ventana implementation).

Hi Tim,
On 03/04/2014 08:01, Tim Harvey wrote:
This can be used to pass info between the SPL and u-boot.
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/include/asm/arch-mx6/sys_proto.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 38851a1..f43e09c 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -39,4 +39,9 @@ int mxs_wait_mask_set(struct mxs_register_32 *reg, int mxs_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned int timeout);
+struct mx6_spl_data {
- uint8_t boot_mode_idx;
- uint32_t mem_dram_size;
+}; #endif
I see checking your patch that the MXS uses the same concept. And as far as I can see, boot_mode_idx is used only to print the boot devioce
However, we have not generally a concept to pass data between SPL and u-boot. My question is even if it is really needed. The size of DRAM is retrived at run time by u-boot running get_ram_size(), that is a better solution.
SPL is thought to generally load an image (of course, in most cases it is u-boot). In Falcon mode, the kernel is started without running u-boot, making this structure useless. Do we really need such a way (but then, it must be generalized as SPL API), or can we get rid of it ?
Best regards, Stefano Babic

On Mon, Apr 14, 2014 at 5:35 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
I see checking your patch that the MXS uses the same concept. And as far as I can see, boot_mode_idx is used only to print the boot devioce
Stefano,
yes, that is where I got the concept from.
However, we have not generally a concept to pass data between SPL and u-boot. My question is even if it is really needed. The size of DRAM is retrived at run time by u-boot running get_ram_size(), that is a better solution.
I've been told this before, but I've found that get_ram_size() will hang on an i.MX6 if you pass it a maxsize larger than the memory in your system. Perhaps you can verify you see the same behavior?
SPL is thought to generally load an image (of course, in most cases it is u-boot). In Falcon mode, the kernel is started without running u-boot, making this structure useless. Do we really need such a way (but then, it must be generalized as SPL API), or can we get rid of it ?
As we have an EEPROM on the board that tells us the physical ram size, I use that to avoid the lockup. Eventually I would like to read and validate the entire EEPROM once in SPL and pass this to u-boot.img to avoid reading and validating it again. I think this is a good example of why sharing data between SPL and u-boot.img could be useful.
Regards,
Tim

Hi Tim,
On 17/04/2014 08:07, Tim Harvey wrote:
On Mon, Apr 14, 2014 at 5:35 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
I see checking your patch that the MXS uses the same concept. And as far as I can see, boot_mode_idx is used only to print the boot devioce
Stefano,
yes, that is where I got the concept from.
Well, it slipped into mainline, but adding such a structure only to have a better print is not very useful...
I've been told this before, but I've found that get_ram_size() will hang on an i.MX6 if you pass it a maxsize larger than the memory in your system. Perhaps you can verify you see the same behavior?
get_ram_size() works if the memory is accessible, that means that no exception is generated when it tries to access. If the RAM controller is programmed for a larger amount of memory, because you can have board with different capacity of RAM, get_ram_size() finds dynamically the soldered value.
However, if the RAM controller is programmed for an amount of RAM smaller as what get_ram_size() tries to identify, an exception is raised. In get_ram_size(start, size) we pass the maximum amount of memory that the function is allowed to check. I can imagine we are running in this case. Checking on i.MX6, we have both boards checking the size with get_ram_size() as mx6sabresd, as well as boards fixing at compile time the value of the RAM (nitrogen6x).
SPL is thought to generally load an image (of course, in most cases it is u-boot). In Falcon mode, the kernel is started without running u-boot, making this structure useless. Do we really need such a way (but then, it must be generalized as SPL API), or can we get rid of it ?
As we have an EEPROM on the board that tells us the physical ram size, I use that to avoid the lockup.
It seems weird. There is several boards in mainline (I am sure about Freescale's PowerPC) discovering the mounted RAM. Of course, this is simpler if many parameters (row/columns/...) are the same, I am not sure about this. Are we sure it is not possible here ? What does it happen with an inconsistent value in EEprom ?
Eventually I would like to read and validate the entire EEPROM once in SPL and pass this to u-boot.img to avoid reading and validating it again. I think this is a good example of why sharing data between SPL and u-boot.img could be useful.
I am not sure, and I doubt it is a good idea to use persistent data to store that. It is potentially dangerous, and if some reasons the EEprom is changed, the board could not boot at all.
On the other side, I like the current concept that the SPL is simply a loader and can load images of different types, and fixing an API between SPL and U-Boot goes against this concept.
Best regards, Stefano Babic

Hi Stefano, Tim,
On 04/17/14 12:30, Stefano Babic wrote:
Hi Tim,
On 17/04/2014 08:07, Tim Harvey wrote:
On Mon, Apr 14, 2014 at 5:35 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
I see checking your patch that the MXS uses the same concept. And as far as I can see, boot_mode_idx is used only to print the boot devioce
Stefano,
yes, that is where I got the concept from.
Well, it slipped into mainline, but adding such a structure only to have a better print is not very useful...
I've been told this before, but I've found that get_ram_size() will hang on an i.MX6 if you pass it a maxsize larger than the memory in your system. Perhaps you can verify you see the same behavior?
get_ram_size() works if the memory is accessible, that means that no exception is generated when it tries to access. If the RAM controller is programmed for a larger amount of memory, because you can have board with different capacity of RAM, get_ram_size() finds dynamically the soldered value.
However, if the RAM controller is programmed for an amount of RAM smaller as what get_ram_size() tries to identify, an exception is raised. In get_ram_size(start, size) we pass the maximum amount of memory that the function is allowed to check. I can imagine we are running in this case. Checking on i.MX6, we have both boards checking the size with get_ram_size() as mx6sabresd, as well as boards fixing at compile time the value of the RAM (nitrogen6x).
get_ram_size() works on cm-fx6 all DRAM configurations.
SPL is thought to generally load an image (of course, in most cases it is u-boot). In Falcon mode, the kernel is started without running u-boot, making this structure useless. Do we really need such a way (but then, it must be generalized as SPL API), or can we get rid of it ?
As we have an EEPROM on the board that tells us the physical ram size, I use that to avoid the lockup.
It seems weird. There is several boards in mainline (I am sure about Freescale's PowerPC) discovering the mounted RAM. Of course, this is simpler if many parameters (row/columns/...) are the same, I am not sure about this.
Even if the parameters are different, this should not result in lockup... AFAICS, lockup of that type has nothing to do with the DRAM itself, but the controller configuration.
Are we sure it is not possible here ? What does it happen with an inconsistent value in EEprom ?
Eventually I would like to read and validate the entire EEPROM once in SPL and pass this to u-boot.img to avoid reading and validating it again. I think this is a good example of why sharing data between SPL and u-boot.img could be useful.
I am not sure, and I doubt it is a good idea to use persistent data to store that. It is potentially dangerous, and if some reasons the EEprom is changed, the board could not boot at all.
This is more a question of design and definition of what purpose the eeprom should serve, so I would let the vendor decide if he wants to depend on eeprom or not.
On the other side, I like the current concept that the SPL is simply a loader and can load images of different types, and fixing an API between SPL and U-Boot goes against this concept.
I agree on this one, there is no real need (at least currently) to introduce such an API.
Also, there are cases (e.g. cm-fx6) where the DRAM size can be determined by just reading the MMDC configuration and thus spare additional get_ram_size() call from U-Boot.

Hi Igor, hi Tim
On 17/04/2014 13:22, Igor Grinberg wrote:
get_ram_size() works on cm-fx6 all DRAM configurations.
As on most boards in mainline ;-)
SPL is thought to generally load an image (of course, in most cases it is u-boot). In Falcon mode, the kernel is started without running u-boot, making this structure useless. Do we really need such a way (but then, it must be generalized as SPL API), or can we get rid of it ?
As we have an EEPROM on the board that tells us the physical ram size, I use that to avoid the lockup.
It seems weird. There is several boards in mainline (I am sure about Freescale's PowerPC) discovering the mounted RAM. Of course, this is simpler if many parameters (row/columns/...) are the same, I am not sure about this.
Even if the parameters are different, this should not result in lockup... AFAICS, lockup of that type has nothing to do with the DRAM itself, but the controller configuration.
Exactly, this is what I meant. Thanks for clarifying it better.
Are we sure it is not possible here ? What does it happen with an inconsistent value in EEprom ?
Eventually I would like to read and validate the entire EEPROM once in SPL and pass this to u-boot.img to avoid reading and validating it again. I think this is a good example of why sharing data between SPL and u-boot.img could be useful.
I am not sure, and I doubt it is a good idea to use persistent data to store that. It is potentially dangerous, and if some reasons the EEprom is changed, the board could not boot at all.
This is more a question of design and definition of what purpose the eeprom should serve, so I would let the vendor decide if he wants to depend on eeprom or not.
Agree. Parsing and evaluating vendor specific information can be done inside board specific part, as now in read_eeprom inside gw_ventana.c.
Anyway, if there is a way to detect at runtime the hardware configuration, it remains a better way as to store the size into the Eeprom.
Best regards, Stefano

On Thu, Apr 17, 2014 at 4:44 AM, Stefano Babic sbabic@denx.de wrote:
Hi Igor, hi Tim
On 17/04/2014 13:22, Igor Grinberg wrote:
get_ram_size() works on cm-fx6 all DRAM configurations.
As on most boards in mainline ;-)
It looks like I mis-interpreted the failure. This issue is that get_ram_size() only works with powers of 2 and maxes out at 2GB due to 32bit addressing. I was simply passing in a bogus value. I'm not sure how you would deal with detecting systems with 4GB but I don't need to support that for my boards currently.
SPL is thought to generally load an image (of course, in most cases it is u-boot). In Falcon mode, the kernel is started without running u-boot, making this structure useless. Do we really need such a way (but then, it must be generalized as SPL API), or can we get rid of it ?
As we have an EEPROM on the board that tells us the physical ram size, I use that to avoid the lockup.
It seems weird. There is several boards in mainline (I am sure about Freescale's PowerPC) discovering the mounted RAM. Of course, this is simpler if many parameters (row/columns/...) are the same, I am not sure about this.
Even if the parameters are different, this should not result in lockup... AFAICS, lockup of that type has nothing to do with the DRAM itself, but the controller configuration.
Exactly, this is what I meant. Thanks for clarifying it better.
Are we sure it is not possible here ? What does it happen with an inconsistent value in EEprom ?
Eventually I would like to read and validate the entire EEPROM once in SPL and pass this to u-boot.img to avoid reading and validating it again. I think this is a good example of why sharing data between SPL and u-boot.img could be useful.
I am not sure, and I doubt it is a good idea to use persistent data to store that. It is potentially dangerous, and if some reasons the EEprom is changed, the board could not boot at all.
This is more a question of design and definition of what purpose the eeprom should serve, so I would let the vendor decide if he wants to depend on eeprom or not.
Agree. Parsing and evaluating vendor specific information can be done inside board specific part, as now in read_eeprom inside gw_ventana.c.
Anyway, if there is a way to detect at runtime the hardware configuration, it remains a better way as to store the size into the Eeprom.
I agree and I definitely see the merits of completely de-coupling the SPL from u-boot.img so I will resort to reading the EEPROM in both places.
Regards,
Tim

On 04/18/14 09:35, Tim Harvey wrote:
On Thu, Apr 17, 2014 at 4:44 AM, Stefano Babic sbabic@denx.de wrote:
Hi Igor, hi Tim
On 17/04/2014 13:22, Igor Grinberg wrote:
get_ram_size() works on cm-fx6 all DRAM configurations.
As on most boards in mainline ;-)
It looks like I mis-interpreted the failure. This issue is that get_ram_size() only works with powers of 2 and maxes out at 2GB due to 32bit addressing. I was simply passing in a bogus value. I'm not sure how you would deal with detecting systems with 4GB but I don't need to support that for my boards currently.
cm-fx6 supports 4GB and detects it properly.

On Sun, Apr 20, 2014 at 12:52 AM, Igor Grinberg grinberg@compulab.co.il wrote:
On 04/18/14 09:35, Tim Harvey wrote:
On Thu, Apr 17, 2014 at 4:44 AM, Stefano Babic sbabic@denx.de wrote:
Hi Igor, hi Tim
On 17/04/2014 13:22, Igor Grinberg wrote:
get_ram_size() works on cm-fx6 all DRAM configurations.
As on most boards in mainline ;-)
It looks like I mis-interpreted the failure. This issue is that get_ram_size() only works with powers of 2 and maxes out at 2GB due to 32bit addressing. I was simply passing in a bogus value. I'm not sure how you would deal with detecting systems with 4GB but I don't need to support that for my boards currently.
cm-fx6 supports 4GB and detects it properly.
Igor,
That's interesting. What value are you passing get_ram_size() then? Where is your code? I don't see any cm-fx6 in mainline or posted patchsets.
Tim

Hi Tim,
On 04/21/14 21:28, Tim Harvey wrote:
On Sun, Apr 20, 2014 at 12:52 AM, Igor Grinberg grinberg@compulab.co.il wrote:
On 04/18/14 09:35, Tim Harvey wrote:
On Thu, Apr 17, 2014 at 4:44 AM, Stefano Babic sbabic@denx.de wrote:
Hi Igor, hi Tim
On 17/04/2014 13:22, Igor Grinberg wrote:
get_ram_size() works on cm-fx6 all DRAM configurations.
As on most boards in mainline ;-)
It looks like I mis-interpreted the failure. This issue is that get_ram_size() only works with powers of 2 and maxes out at 2GB due to 32bit addressing. I was simply passing in a bogus value. I'm not sure how you would deal with detecting systems with 4GB but I don't need to support that for my boards currently.
cm-fx6 supports 4GB and detects it properly.
Igor,
That's interesting. What value are you passing get_ram_size() then?
Well, we do it in several get_ram_size() calls and decide according to returned results.
Where is your code? I don't see any cm-fx6 in mainline or posted patchsets.
Right, it is work in progress. Currently, it is based on 2014.01. Once it is ready, we re-base and post it.

This is an attempt at using a macro to allow mx6dl-ddr.h and mx6q-ddr.h registers to be used together which is needed for an SPL bootloader that can run on either CPU's and must configure MMDC iomux dynamically.
I am trying to come up with a solution similar to Eric's approach with the similar issue regarding IMX pinmux but this approach is broken in that imximage will choke on the cfgtmp file due to the fact that the pre-processor won't use the enum's as it did the #defines. I'm looking for some positive suggestions here or perhaps someone else can come up with a solution for this particular issue which I haven't been able to resolve.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 29 +++++++++-- arch/arm/include/asm/arch-mx6/mx6dl-ddr.h | 82 ++++++++++++++++--------------- arch/arm/include/asm/arch-mx6/mx6q-ddr.h | 82 ++++++++++++++++--------------- 3 files changed, 108 insertions(+), 85 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 43d377a..6ac857e 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -6,15 +6,34 @@ #ifndef __ASM_ARCH_MX6_DDR_H__ #define __ASM_ARCH_MX6_DDR_H__
-#ifdef CONFIG_MX6Q +#define MX6_ADDR_DECLARE(prefix, name, addr) \ + prefix##name = addr + +#ifdef CONFIG_MX6QDL +enum { +#define MX6_ADDR_DECL(name, addr) \ + MX6_ADDR_DECLARE(MX6Q_, name, addr), #include "mx6q-ddr.h" -#else -#if defined(CONFIG_MX6DL) || defined(CONFIG_MX6S) +}; +#undef MX6_ADDR_DECL + +enum { +#define MX6_ADDR_DECL(name, addr) \ + MX6_ADDR_DECLARE(MX6DL_, name, addr), +#include "mx6dl-ddr.h" +}; + +#elif defined(CONFIG_MX6Q) +#define MX6_ADDR_DECL(name, addr) \ + MX6_ADDR_DECLARE(MX6_, name, addr), +#include "mx6q-ddr.h" +#elif defined(CONFIG_MX6DL) || defined(CONFIG_MX6S) +#define MX6_ADDR_DECL(name, addr) \ + MX6_ADDR_DECLARE(MX6_, name, addr), #include "mx6dl-ddr.h" #else #error "Please select cpu" -#endif /* CONFIG_MX6DL or CONFIG_MX6S */ -#endif /* CONFIG_MX6Q */ +#endif
#define MX6_MMDC_P0_MDCTL 0x021b0000 #define MX6_MMDC_P0_MDPDC 0x021b0004 diff --git a/arch/arm/include/asm/arch-mx6/mx6dl-ddr.h b/arch/arm/include/asm/arch-mx6/mx6dl-ddr.h index 1eb4b3c..4828974 100644 --- a/arch/arm/include/asm/arch-mx6/mx6dl-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6dl-ddr.h @@ -6,54 +6,56 @@ #ifndef __ASM_ARCH_MX6DLS_DDR_H__ #define __ASM_ARCH_MX6DLS_DDR_H__
+#ifndef CONFIG_MX6QDL #ifndef CONFIG_MX6DL #ifndef CONFIG_MX6S #error "wrong CPU" #endif #endif +#endif
-#define MX6_IOM_DRAM_DQM0 0x020e0470 -#define MX6_IOM_DRAM_DQM1 0x020e0474 -#define MX6_IOM_DRAM_DQM2 0x020e0478 -#define MX6_IOM_DRAM_DQM3 0x020e047c -#define MX6_IOM_DRAM_DQM4 0x020e0480 -#define MX6_IOM_DRAM_DQM5 0x020e0484 -#define MX6_IOM_DRAM_DQM6 0x020e0488 -#define MX6_IOM_DRAM_DQM7 0x020e048c +MX6_ADDR_DECL(IOM_DRAM_DQM0, 0x020e0470) +MX6_ADDR_DECL(IOM_DRAM_DQM1, 0x020e0474) +MX6_ADDR_DECL(IOM_DRAM_DQM2, 0x020e0478) +MX6_ADDR_DECL(IOM_DRAM_DQM3, 0x020e047c) +MX6_ADDR_DECL(IOM_DRAM_DQM4, 0x020e0480) +MX6_ADDR_DECL(IOM_DRAM_DQM5, 0x020e0484) +MX6_ADDR_DECL(IOM_DRAM_DQM6, 0x020e0488) +MX6_ADDR_DECL(IOM_DRAM_DQM7, 0x020e048c)
-#define MX6_IOM_DRAM_CAS 0x020e0464 -#define MX6_IOM_DRAM_RAS 0x020e0490 -#define MX6_IOM_DRAM_RESET 0x020e0494 -#define MX6_IOM_DRAM_SDCLK_0 0x020e04ac -#define MX6_IOM_DRAM_SDCLK_1 0x020e04b0 -#define MX6_IOM_DRAM_SDBA2 0x020e04a0 -#define MX6_IOM_DRAM_SDCKE0 0x020e04a4 -#define MX6_IOM_DRAM_SDCKE1 0x020e04a8 -#define MX6_IOM_DRAM_SDODT0 0x020e04b4 -#define MX6_IOM_DRAM_SDODT1 0x020e04b8 +MX6_ADDR_DECL(IOM_DRAM_CAS, 0x020e0464) +MX6_ADDR_DECL(IOM_DRAM_RAS, 0x020e0490) +MX6_ADDR_DECL(IOM_DRAM_RESET, 0x020e0494) +MX6_ADDR_DECL(IOM_DRAM_SDCLK_0, 0x020e04ac) +MX6_ADDR_DECL(IOM_DRAM_SDCLK_1, 0x020e04b0) +MX6_ADDR_DECL(IOM_DRAM_SDBA2, 0x020e04a0) +MX6_ADDR_DECL(IOM_DRAM_SDCKE0, 0x020e04a4) +MX6_ADDR_DECL(IOM_DRAM_SDCKE1, 0x020e04a8) +MX6_ADDR_DECL(IOM_DRAM_SDODT0, 0x020e04b4) +MX6_ADDR_DECL(IOM_DRAM_SDODT1, 0x020e04b8)
-#define MX6_IOM_DRAM_SDQS0 0x020e04bc -#define MX6_IOM_DRAM_SDQS1 0x020e04c0 -#define MX6_IOM_DRAM_SDQS2 0x020e04c4 -#define MX6_IOM_DRAM_SDQS3 0x020e04c8 -#define MX6_IOM_DRAM_SDQS4 0x020e04cc -#define MX6_IOM_DRAM_SDQS5 0x020e04d0 -#define MX6_IOM_DRAM_SDQS6 0x020e04d4 -#define MX6_IOM_DRAM_SDQS7 0x020e04d8 +MX6_ADDR_DECL(IOM_DRAM_SDQS0, 0x020e04bc) +MX6_ADDR_DECL(IOM_DRAM_SDQS1, 0x020e04c0) +MX6_ADDR_DECL(IOM_DRAM_SDQS2, 0x020e04c4) +MX6_ADDR_DECL(IOM_DRAM_SDQS3, 0x020e04c8) +MX6_ADDR_DECL(IOM_DRAM_SDQS4, 0x020e04cc) +MX6_ADDR_DECL(IOM_DRAM_SDQS5, 0x020e04d0) +MX6_ADDR_DECL(IOM_DRAM_SDQS6, 0x020e04d4) +MX6_ADDR_DECL(IOM_DRAM_SDQS7, 0x020e04d8)
-#define MX6_IOM_GRP_B0DS 0x020e0764 -#define MX6_IOM_GRP_B1DS 0x020e0770 -#define MX6_IOM_GRP_B2DS 0x020e0778 -#define MX6_IOM_GRP_B3DS 0x020e077c -#define MX6_IOM_GRP_B4DS 0x020e0780 -#define MX6_IOM_GRP_B5DS 0x020e0784 -#define MX6_IOM_GRP_B6DS 0x020e078c -#define MX6_IOM_GRP_B7DS 0x020e0748 -#define MX6_IOM_GRP_ADDDS 0x020e074c -#define MX6_IOM_DDRMODE_CTL 0x020e0750 -#define MX6_IOM_GRP_DDRPKE 0x020e0754 -#define MX6_IOM_GRP_DDRMODE 0x020e0760 -#define MX6_IOM_GRP_CTLDS 0x020e076c -#define MX6_IOM_GRP_DDR_TYPE 0x020e0774 +MX6_ADDR_DECL(IOM_GRP_B0DS, 0x020e0764) +MX6_ADDR_DECL(IOM_GRP_B1DS, 0x020e0770) +MX6_ADDR_DECL(IOM_GRP_B2DS, 0x020e0778) +MX6_ADDR_DECL(IOM_GRP_B3DS, 0x020e077c) +MX6_ADDR_DECL(IOM_GRP_B4DS, 0x020e0780) +MX6_ADDR_DECL(IOM_GRP_B5DS, 0x020e0784) +MX6_ADDR_DECL(IOM_GRP_B6DS, 0x020e078c) +MX6_ADDR_DECL(IOM_GRP_B7DS, 0x020e0748) +MX6_ADDR_DECL(IOM_GRP_ADDDS, 0x020e074c) +MX6_ADDR_DECL(IOM_DDRMODE_CTL, 0x020e0750) +MX6_ADDR_DECL(IOM_GRP_DDRPKE, 0x020e0754) +MX6_ADDR_DECL(IOM_GRP_DDRMODE, 0x020e0760) +MX6_ADDR_DECL(IOM_GRP_CTLDS, 0x020e076c) +MX6_ADDR_DECL(IOM_GRP_DDR_TYPE, 0x020e0774)
#endif /*__ASM_ARCH_MX6S_DDR_H__ */ diff --git a/arch/arm/include/asm/arch-mx6/mx6q-ddr.h b/arch/arm/include/asm/arch-mx6/mx6q-ddr.h index 0aa94cf..bd9cf1a 100644 --- a/arch/arm/include/asm/arch-mx6/mx6q-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6q-ddr.h @@ -6,52 +6,54 @@ #ifndef __ASM_ARCH_MX6Q_DDR_H__ #define __ASM_ARCH_MX6Q_DDR_H__
+#ifndef CONFIG_MX6QDL #ifndef CONFIG_MX6Q #error "wrong CPU" #endif +#endif
-#define MX6_IOM_DRAM_DQM0 0x020e05ac -#define MX6_IOM_DRAM_DQM1 0x020e05b4 -#define MX6_IOM_DRAM_DQM2 0x020e0528 -#define MX6_IOM_DRAM_DQM3 0x020e0520 -#define MX6_IOM_DRAM_DQM4 0x020e0514 -#define MX6_IOM_DRAM_DQM5 0x020e0510 -#define MX6_IOM_DRAM_DQM6 0x020e05bc -#define MX6_IOM_DRAM_DQM7 0x020e05c4 +MX6_ADDR_DECL(IOM_DRAM_DQM0, 0x020e05ac) +MX6_ADDR_DECL(IOM_DRAM_DQM1, 0x020e05b4) +MX6_ADDR_DECL(IOM_DRAM_DQM2, 0x020e0528) +MX6_ADDR_DECL(IOM_DRAM_DQM3, 0x020e0520) +MX6_ADDR_DECL(IOM_DRAM_DQM4, 0x020e0514) +MX6_ADDR_DECL(IOM_DRAM_DQM5, 0x020e0510) +MX6_ADDR_DECL(IOM_DRAM_DQM6, 0x020e05bc) +MX6_ADDR_DECL(IOM_DRAM_DQM7, 0x020e05c4)
-#define MX6_IOM_DRAM_CAS 0x020e056c -#define MX6_IOM_DRAM_RAS 0x020e0578 -#define MX6_IOM_DRAM_RESET 0x020e057c -#define MX6_IOM_DRAM_SDCLK_0 0x020e0588 -#define MX6_IOM_DRAM_SDCLK_1 0x020e0594 -#define MX6_IOM_DRAM_SDBA2 0x020e058c -#define MX6_IOM_DRAM_SDCKE0 0x020e0590 -#define MX6_IOM_DRAM_SDCKE1 0x020e0598 -#define MX6_IOM_DRAM_SDODT0 0x020e059c -#define MX6_IOM_DRAM_SDODT1 0x020e05a0 +MX6_ADDR_DECL(IOM_DRAM_CAS, 0x020e056c) +MX6_ADDR_DECL(IOM_DRAM_RAS, 0x020e0578) +MX6_ADDR_DECL(IOM_DRAM_RESET, 0x020e057c) +MX6_ADDR_DECL(IOM_DRAM_SDCLK_0, 0x020e0588) +MX6_ADDR_DECL(IOM_DRAM_SDCLK_1, 0x020e0594) +MX6_ADDR_DECL(IOM_DRAM_SDBA2, 0x020e058c) +MX6_ADDR_DECL(IOM_DRAM_SDCKE0, 0x020e0590) +MX6_ADDR_DECL(IOM_DRAM_SDCKE1, 0x020e0598) +MX6_ADDR_DECL(IOM_DRAM_SDODT0, 0x020e059c) +MX6_ADDR_DECL(IOM_DRAM_SDODT1, 0x020e05a0)
-#define MX6_IOM_DRAM_SDQS0 0x020e05a8 -#define MX6_IOM_DRAM_SDQS1 0x020e05b0 -#define MX6_IOM_DRAM_SDQS2 0x020e0524 -#define MX6_IOM_DRAM_SDQS3 0x020e051c -#define MX6_IOM_DRAM_SDQS4 0x020e0518 -#define MX6_IOM_DRAM_SDQS5 0x020e050c -#define MX6_IOM_DRAM_SDQS6 0x020e05b8 -#define MX6_IOM_DRAM_SDQS7 0x020e05c0 +MX6_ADDR_DECL(IOM_DRAM_SDQS0, 0x020e05a8) +MX6_ADDR_DECL(IOM_DRAM_SDQS1, 0x020e05b0) +MX6_ADDR_DECL(IOM_DRAM_SDQS2, 0x020e0524) +MX6_ADDR_DECL(IOM_DRAM_SDQS3, 0x020e051c) +MX6_ADDR_DECL(IOM_DRAM_SDQS4, 0x020e0518) +MX6_ADDR_DECL(IOM_DRAM_SDQS5, 0x020e050c) +MX6_ADDR_DECL(IOM_DRAM_SDQS6, 0x020e05b8) +MX6_ADDR_DECL(IOM_DRAM_SDQS7, 0x020e05c0)
-#define MX6_IOM_GRP_B0DS 0x020e0784 -#define MX6_IOM_GRP_B1DS 0x020e0788 -#define MX6_IOM_GRP_B2DS 0x020e0794 -#define MX6_IOM_GRP_B3DS 0x020e079c -#define MX6_IOM_GRP_B4DS 0x020e07a0 -#define MX6_IOM_GRP_B5DS 0x020e07a4 -#define MX6_IOM_GRP_B6DS 0x020e07a8 -#define MX6_IOM_GRP_B7DS 0x020e0748 -#define MX6_IOM_GRP_ADDDS 0x020e074c -#define MX6_IOM_DDRMODE_CTL 0x020e0750 -#define MX6_IOM_GRP_DDRPKE 0x020e0758 -#define MX6_IOM_GRP_DDRMODE 0x020e0774 -#define MX6_IOM_GRP_CTLDS 0x020e078c -#define MX6_IOM_GRP_DDR_TYPE 0x020e0798 +MX6_ADDR_DECL(IOM_GRP_B0DS, 0x020e0784) +MX6_ADDR_DECL(IOM_GRP_B1DS, 0x020e0788) +MX6_ADDR_DECL(IOM_GRP_B2DS, 0x020e0794) +MX6_ADDR_DECL(IOM_GRP_B3DS, 0x020e079c) +MX6_ADDR_DECL(IOM_GRP_B4DS, 0x020e07a0) +MX6_ADDR_DECL(IOM_GRP_B5DS, 0x020e07a4) +MX6_ADDR_DECL(IOM_GRP_B6DS, 0x020e07a8) +MX6_ADDR_DECL(IOM_GRP_B7DS, 0x020e0748) +MX6_ADDR_DECL(IOM_GRP_ADDDS, 0x020e074c) +MX6_ADDR_DECL(IOM_DDRMODE_CTL, 0x020e0750) +MX6_ADDR_DECL(IOM_GRP_DDRPKE, 0x020e0758) +MX6_ADDR_DECL(IOM_GRP_DDRMODE, 0x020e0774) +MX6_ADDR_DECL(IOM_GRP_CTLDS, 0x020e078c) +MX6_ADDR_DECL(IOM_GRP_DDR_TYPE, 0x020e0798)
#endif /*__ASM_ARCH_MX6Q_DDR_H__ */

Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
This is an attempt at using a macro to allow mx6dl-ddr.h and mx6q-ddr.h registers to be used together which is needed for an SPL bootloader that can run on either CPU's and must configure MMDC iomux dynamically.
I am trying to come up with a solution similar to Eric's approach with the similar issue regarding IMX pinmux but this approach is broken in that imximage will choke on the cfgtmp file due to the fact that the pre-processor won't use the enum's as it did the #defines. I'm looking for some positive suggestions here or perhaps someone else can come up with a solution for this particular issue which I haven't been able to resolve.
Why can't you just rename the register name #defines without enclosing them in an anonymous enum? Then they could coexist and will be usable by imximage.

On Wed, Apr 9, 2014 at 7:57 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
This is an attempt at using a macro to allow mx6dl-ddr.h and mx6q-ddr.h registers to be used together which is needed for an SPL bootloader that can run on either CPU's and must configure MMDC iomux dynamically.
I am trying to come up with a solution similar to Eric's approach with the similar issue regarding IMX pinmux but this approach is broken in that imximage will choke on the cfgtmp file due to the fact that the pre-processor won't use the enum's as it did the #defines. I'm looking for some positive suggestions here or perhaps someone else can come up with a solution for this particular issue which I haven't been able to resolve.
Why can't you just rename the register name #defines without enclosing them in an anonymous enum? Then they could coexist and will be usable by imximage.
-- Regards, Nikita.
Nikita,
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL. Furthermore, then cfg files use the pre-processor only, which is why the enums I chose don't work for non-SPL. For SPL, I need both sets of #defines (here they could be enums however) so I would have to duplicate all of the #defines in mx6q_pins.h and mx6dl_pins.h to provide both the MX6_ and the MX6Q_/MX6DL_ #defines. I'm ok with submitting that duplication if there is no other way.
Am I missing something completely obvious here? Maybe an example of what you are thinking would help me understand.
Regards,
Tim

On 04/09/2014 06:46 PM, Tim Harvey wrote:
On Wed, Apr 9, 2014 at 7:57 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
This is an attempt at using a macro to allow mx6dl-ddr.h and mx6q-ddr.h registers to be used together which is needed for an SPL bootloader that can run on either CPU's and must configure MMDC iomux dynamically.
I am trying to come up with a solution similar to Eric's approach with the similar issue regarding IMX pinmux but this approach is broken in that imximage will choke on the cfgtmp file due to the fact that the pre-processor won't use the enum's as it did the #defines. I'm looking for some positive suggestions here or perhaps someone else can come up with a solution for this particular issue which I haven't been able to resolve.
Why can't you just rename the register name #defines without enclosing them in an anonymous enum? Then they could coexist and will be usable by imximage.
-- Regards, Nikita.
Nikita,
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL.
OK now I understand. It seems to me that you only have this problem because you are using these address #defines as values for mx6_mmdc_ioregs structs to define a register mapping. You can also define this mapping by using a struct template that matches the register layout and a base address, both of which change between CPU types.
You can find an example of this in the Wandboard SPL implementation. It's not in mainline ATM so you'll have to download their BSP. The template + base addr method also doesn't use up additional memory to define this layout, which is a point in its favor.
Regards,
Tim

On 04/10/2014 05:08 PM, Nikita Kiryanov wrote:
On 04/09/2014 06:46 PM, Tim Harvey wrote:
On Wed, Apr 9, 2014 at 7:57 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
This is an attempt at using a macro to allow mx6dl-ddr.h and mx6q-ddr.h registers to be used together which is needed for an SPL bootloader that can run on either CPU's and must configure MMDC iomux dynamically.
I am trying to come up with a solution similar to Eric's approach with the similar issue regarding IMX pinmux but this approach is broken in that imximage will choke on the cfgtmp file due to the fact that the pre-processor won't use the enum's as it did the #defines. I'm looking for some positive suggestions here or perhaps someone else can come up with a solution for this particular issue which I haven't been able to resolve.
Why can't you just rename the register name #defines without enclosing them in an anonymous enum? Then they could coexist and will be usable by imximage.
-- Regards, Nikita.
Nikita,
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL.
OK now I understand. It seems to me that you only have this problem because you are using these address #defines as values for mx6_mmdc_ioregs structs to define a register mapping. You can also define this mapping by using a struct template that matches the register layout and a base address, both of which change between CPU types.
You can find an example of this in the Wandboard SPL implementation.
Here I'm referring to the file arch/arm/include/asm/arch-mx6/mx6_ddr_regs.h (which I'm guessing you may have already seen based on your comment on patch 11...)
It's not in mainline ATM so you'll have to download their BSP. The template + base addr method also doesn't use up additional memory to define this layout, which is a point in its favor.
Regards,
Tim

On Thu, Apr 10, 2014 at 7:51 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
On 04/10/2014 05:08 PM, Nikita Kiryanov wrote:
<snip>
Here I'm referring to the file arch/arm/include/asm/arch-mx6/mx6_ddr_regs.h (which I'm guessing you may have already seen based on your comment on patch 11...)
Nikita,
Yes, I started with that but I thought from the previous discussion that the structures were disliked. I will revert back to that approach for my v2 patch and see how well its received.
Regards,
Tim

Hi Tim, hi Nikita,
On 10/04/2014 16:08, Nikita Kiryanov wrote:
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL.
OK now I understand. It seems to me that you only have this problem because you are using these address #defines as values for mx6_mmdc_ioregs structs to define a register mapping. You can also define this mapping by using a struct template that matches the register layout and a base address, both of which change between CPU types.
Reason to do in this way is the thought that the layout among the processsors can be completely different, thing that for other area is also true. This was discussed also in a previous RFC by Eric:
http://lists.denx.de/pipermail/u-boot/2013-November/166665.html
Tim, what about to repost in your patchset Eric's patch ? It completes your patchset and add documentation that is now missing (added Eric in CC if he will complain about this..)
However, if we can recognize the same layout for all three variations (I have only check some registers in 6Q and 6DL layout), using the same structure with a different base address can be even more readable. I admit I have not checked deeply, but it seems at first glance that mx6dq_ctrl and mx6sdl_ctrl in 7/11 share the same layout.
You can find an example of this in the Wandboard SPL implementation. It's not in mainline ATM so you'll have to download their BSP. The template + base addr method also doesn't use up additional memory to define this layout, which is a point in its favor.
If the layout is exactly the same, you could make the structure available to all imx6 flavors.
Best regards, Stefano Babic

Hi Stefano,
On 04/23/2014 10:07 AM, Stefano Babic wrote:
Hi Tim, hi Nikita,
On 10/04/2014 16:08, Nikita Kiryanov wrote:
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL.
OK now I understand. It seems to me that you only have this problem because you are using these address #defines as values for mx6_mmdc_ioregs structs to define a register mapping. You can also define this mapping by using a struct template that matches the register layout and a base address, both of which change between CPU types.
Reason to do in this way is the thought that the layout among the processsors can be completely different, thing that for other area is also true.
This was discussed also in a previous RFC by Eric:
http://lists.denx.de/pipermail/u-boot/2013-November/166665.html
Tim, what about to repost in your patchset Eric's patch ? It completes your patchset and add documentation that is now missing (added Eric in CC if he will complain about this..)
I have no problem with this, but when I did some follow-on work to bring up SPL on Nitrogen6x boards, I recall finding some bugs in that patch set.
I didn't follow up with updates because I ran into some other snags. In particular, our use of SPI-NOR makes it crucial that we be able to download a secondary U-Boot over USB.
However, if we can recognize the same layout for all three variations (I have only check some registers in 6Q and 6DL layout), using the same structure with a different base address can be even more readable. I admit I have not checked deeply, but it seems at first glance that mx6dq_ctrl and mx6sdl_ctrl in 7/11 share the same layout.
There's a lot of commonality, but a quick diff of arch-mx6/mx6q-ddr.h and arch-mx6/mx6dl-ddr.h will show the problem areas.
You can find an example of this in the Wandboard SPL implementation. It's not in mainline ATM so you'll have to download their BSP. The template + base addr method also doesn't use up additional memory to define this layout, which is a point in its favor.
If the layout is exactly the same, you could make the structure available to all imx6 flavors.
Unfortunately, I don't believe it is.
Regards,
Eric

On 04/23/14 22:00, Eric Nelson wrote:
Hi Stefano,
On 04/23/2014 10:07 AM, Stefano Babic wrote:
Hi Tim, hi Nikita,
On 10/04/2014 16:08, Nikita Kiryanov wrote:
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL.
OK now I understand. It seems to me that you only have this problem because you are using these address #defines as values for mx6_mmdc_ioregs structs to define a register mapping. You can also define this mapping by using a struct template that matches the register layout and a base address, both of which change between CPU types.
Reason to do in this way is the thought that the layout among the processsors can be completely different, thing that for other area is also true.
This was discussed also in a previous RFC by Eric:
http://lists.denx.de/pipermail/u-boot/2013-November/166665.html
Tim, what about to repost in your patchset Eric's patch ? It completes your patchset and add documentation that is now missing (added Eric in CC if he will complain about this..)
I have no problem with this, but when I did some follow-on work to bring up SPL on Nitrogen6x boards, I recall finding some bugs in that patch set.
I didn't follow up with updates because I ran into some other snags. In particular, our use of SPI-NOR makes it crucial that we be able to download a secondary U-Boot over USB.
However, if we can recognize the same layout for all three variations (I have only check some registers in 6Q and 6DL layout), using the same structure with a different base address can be even more readable. I admit I have not checked deeply, but it seems at first glance that mx6dq_ctrl and mx6sdl_ctrl in 7/11 share the same layout.
There's a lot of commonality, but a quick diff of arch-mx6/mx6q-ddr.h and arch-mx6/mx6dl-ddr.h will show the problem areas.
You can find an example of this in the Wandboard SPL implementation. It's not in mainline ATM so you'll have to download their BSP. The template + base addr method also doesn't use up additional memory to define this layout, which is a point in its favor.
If the layout is exactly the same, you could make the structure available to all imx6 flavors.
Unfortunately, I don't believe it is.
I also, remember it is not. What Tim says actually makes sense, if layout is not the same, define two structs and choose the right one in runtime.

On Wed, Apr 23, 2014 at 10:07 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim, hi Nikita,
On 10/04/2014 16:08, Nikita Kiryanov wrote:
The cfg files are currently all written to use the IOMUX register names as MX6_ (no Q vs DL) so that a single cfg file can be used for a build-time configuration of IMX6Q or IMX6DL.
OK now I understand. It seems to me that you only have this problem because you are using these address #defines as values for mx6_mmdc_ioregs structs to define a register mapping. You can also define this mapping by using a struct template that matches the register layout and a base address, both of which change between CPU types.
Reason to do in this way is the thought that the layout among the processsors can be completely different, thing that for other area is also true. This was discussed also in a previous RFC by Eric:
http://lists.denx.de/pipermail/u-boot/2013-November/166665.html
Tim, what about to repost in your patchset Eric's patch ? It completes your patchset and add documentation that is now missing (added Eric in CC if he will complain about this..)
The documentation portion of Eric's patch I agreed with for the most part, but in my case I need to take a more flexible approach as I support multiple board variants in a single bootloader that vary a bit in pinmux and GPIO's. For this reason, I don't like the idea of declaring all your iomux in a single structure (Eric's README section 4).
However, if we can recognize the same layout for all three variations (I have only check some registers in 6Q and 6DL layout), using the same structure with a different base address can be even more readable. I admit I have not checked deeply, but it seems at first glance that mx6dq_ctrl and mx6sdl_ctrl in 7/11 share the same layout.
You can find an example of this in the Wandboard SPL implementation. It's not in mainline ATM so you'll have to download their BSP. The template + base addr method also doesn't use up additional memory to define this layout, which is a point in its favor.
If the layout is exactly the same, you could make the structure available to all imx6 flavors.
Best regards, Stefano Babic
They do differ, but that isn't to say one can't just have two memory mapped struct's and pick which one to use based on CPU, which is exactly what Tapani proposed originally and is what is used in the non-mainlined Wandboard. I will be moving to this method in v2.
Regards,
Tim

Hi Tim,
On 09/04/2014 17:46, Tim Harvey wrote:
On Wed, Apr 9, 2014 at 7:57 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
This is an attempt at using a macro to allow mx6dl-ddr.h and mx6q-ddr.h registers to be used together which is needed for an SPL bootloader that can run on either CPU's and must configure MMDC iomux dynamically.
I am trying to come up with a solution similar to Eric's approach with the similar issue regarding IMX pinmux but this approach is broken in that imximage will choke on the cfgtmp file due to the fact that the pre-processor won't use the enum's as it did the #defines. I'm looking for some positive suggestions here or perhaps someone else can come up with a solution for this particular issue which I haven't been able to resolve.
It seems that this patch breaks all other boards. I tried myself and after preprocessing the .cfg file, the resulting file contains structures that mkimage cannot process.
For example, building udoo:
MKIMAGE u-boot.imx
Invalid imximage commands Type - valid names are: BOOT_FROM, BOOT_OFFSET, DATA, CSF, IMAGE_VERSION Error: board/udoo/udoo.cfg.cfgtmp[44] - Invalid command(struct)
In fact, board/udoo/udoo.cfg.cfgtmp contains the structures from /mx6-ddr.h (this patch):
# 15 "include/config.h" 2 # 23 "board/udoo/udoo.cfg" 2 # 1 "/home/stefano/Projects/imx/u-boot-imx/arch/arm/include/asm/arch/mx6-ddr.h" 1 # 15 "/home/stefano/Projects/imx/u-boot-imx/arch/arm/include/asm/arch/mx6-ddr.h" struct mx6_mmdc_ioregs { u32 mmdc_dram_dqm0; u32 mmdc_dram_dqm1; u32 mmdc_dram_dqm2; u32 mmdc_dram_dqm3; u32 mmdc_dram_dqm4; u32 mmdc_dram_dqm5; u32 mmdc_dram_dqm6; u32 mmdc_dram_dqm7; u32 mmdc_dram_cas; u32 mmdc_dram_ras;
and then mkimage stops.
Best regards, Stefano Babic

- add mmdc iomux structs and defines - add mmdc ddr3 structs and defines - add function for configuring iomux based on board-specific regs - add function for configuring mmdc based on board-specific and chip-specific data
The purpose of these structures and functions is to dynamically configure the IMX MMDC per memory bus frequency (dictated by the CPU type), memory bus size, DDR3 chip characteristics, and board-specific calibration data.
An alternative approach would be to simply pass in an entire structure with the values to write to the MMDC registers, however that creates some duplication and propagates 'magic' values which should be able to be calculated. Some of the MMDC registers here are still hard-coded as that is what Freescale recommends by way of their 'DDR3 Script Aid' spreadsheet (DOC-94917) and if need be these can be moved into struct params as well. Additionally if this is agreed to be the right step forward I can put all the shifts and masks for the MMDC registers into #defines in a header.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 542 ++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/mx6-ddr.h | 196 ++++++++++++ 3 files changed, 739 insertions(+) create mode 100644 arch/arm/cpu/armv7/mx6/ddr.c
diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile index d7285fc..6dc9f8e 100644 --- a/arch/arm/cpu/armv7/mx6/Makefile +++ b/arch/arm/cpu/armv7/mx6/Makefile @@ -8,4 +8,5 @@ #
obj-y := soc.o clock.o +obj-$(CONFIG_SPL_BUILD) += ddr.o obj-$(CONFIG_SECURE_BOOT) += hab.o diff --git a/arch/arm/cpu/armv7/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c new file mode 100644 index 0000000..a910a93 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -0,0 +1,542 @@ +/* + * Author: Tim Harvey tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <linux/types.h> +#include <asm/arch/mx6-ddr.h> +#include <asm/arch/sys_proto.h> +#include <asm/io.h> +#include <asm/types.h> + +#if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6Q) +struct mx6_mmdc_ioregs const mx6dq_ctrl = { + .mmdc_dram_dqm0 = MX6Q_IOM_DRAM_DQM0, + .mmdc_dram_dqm1 = MX6Q_IOM_DRAM_DQM1, + .mmdc_dram_dqm2 = MX6Q_IOM_DRAM_DQM2, + .mmdc_dram_dqm3 = MX6Q_IOM_DRAM_DQM3, + .mmdc_dram_dqm4 = MX6Q_IOM_DRAM_DQM4, + .mmdc_dram_dqm5 = MX6Q_IOM_DRAM_DQM5, + .mmdc_dram_dqm6 = MX6Q_IOM_DRAM_DQM6, + .mmdc_dram_dqm7 = MX6Q_IOM_DRAM_DQM7, + .mmdc_dram_cas = MX6Q_IOM_DRAM_CAS, + .mmdc_dram_ras = MX6Q_IOM_DRAM_RAS, + .mmdc_dram_reset = MX6Q_IOM_DRAM_RESET, + .mmdc_dram_sdclk_0 = MX6Q_IOM_DRAM_SDCLK_0, + .mmdc_dram_sdclk_1 = MX6Q_IOM_DRAM_SDCLK_1, + .mmdc_dram_sdba2 = MX6Q_IOM_DRAM_SDBA2, + .mmdc_dram_sdcke0 = MX6Q_IOM_DRAM_SDCKE0, + .mmdc_dram_sdcke1 = MX6Q_IOM_DRAM_SDCKE1, + .mmdc_dram_sdodt0 = MX6Q_IOM_DRAM_SDODT0, + .mmdc_dram_sdodt1 = MX6Q_IOM_DRAM_SDODT1, + .mmdc_dram_sdqs0 = MX6Q_IOM_DRAM_SDQS0, + .mmdc_dram_sdqs1 = MX6Q_IOM_DRAM_SDQS1, + .mmdc_dram_sdqs2 = MX6Q_IOM_DRAM_SDQS2, + .mmdc_dram_sdqs3 = MX6Q_IOM_DRAM_SDQS3, + .mmdc_dram_sdqs4 = MX6Q_IOM_DRAM_SDQS4, + .mmdc_dram_sdqs5 = MX6Q_IOM_DRAM_SDQS5, + .mmdc_dram_sdqs6 = MX6Q_IOM_DRAM_SDQS6, + .mmdc_dram_sdqs7 = MX6Q_IOM_DRAM_SDQS7, + .mmdc_grp_b0ds = MX6Q_IOM_GRP_B0DS, + .mmdc_grp_b1ds = MX6Q_IOM_GRP_B1DS, + .mmdc_grp_b2ds = MX6Q_IOM_GRP_B2DS, + .mmdc_grp_b3ds = MX6Q_IOM_GRP_B3DS, + .mmdc_grp_b4ds = MX6Q_IOM_GRP_B4DS, + .mmdc_grp_b5ds = MX6Q_IOM_GRP_B5DS, + .mmdc_grp_b6ds = MX6Q_IOM_GRP_B6DS, + .mmdc_grp_b7ds = MX6Q_IOM_GRP_B7DS, + .mmdc_grp_addds = MX6Q_IOM_GRP_ADDDS, + .mmdc_grp_ddrpke = MX6Q_IOM_GRP_DDRPKE, + .mmdc_grp_ctlds = MX6Q_IOM_GRP_CTLDS, + .mmdc_grp_ddr_type = MX6Q_IOM_GRP_DDR_TYPE, + .mmdc_ddrmode_ctl = MX6Q_IOM_DDRMODE_CTL, + .mmdc_grp_ddrmode = MX6Q_IOM_GRP_DDRMODE, +}; +#endif + +#if defined(CONFIG_MX6QDL) || defined(CONFIG_MX6DL) +struct mx6_mmdc_ioregs const mx6sdl_ctrl = { + .mmdc_dram_dqm0 = MX6DL_IOM_DRAM_DQM0, + .mmdc_dram_dqm1 = MX6DL_IOM_DRAM_DQM1, + .mmdc_dram_dqm2 = MX6DL_IOM_DRAM_DQM2, + .mmdc_dram_dqm3 = MX6DL_IOM_DRAM_DQM3, + .mmdc_dram_dqm4 = MX6DL_IOM_DRAM_DQM4, + .mmdc_dram_dqm5 = MX6DL_IOM_DRAM_DQM5, + .mmdc_dram_dqm6 = MX6DL_IOM_DRAM_DQM6, + .mmdc_dram_dqm7 = MX6DL_IOM_DRAM_DQM7, + .mmdc_dram_cas = MX6DL_IOM_DRAM_CAS, + .mmdc_dram_ras = MX6DL_IOM_DRAM_RAS, + .mmdc_dram_reset = MX6DL_IOM_DRAM_RESET, + .mmdc_dram_sdclk_0 = MX6DL_IOM_DRAM_SDCLK_0, + .mmdc_dram_sdclk_1 = MX6DL_IOM_DRAM_SDCLK_1, + .mmdc_dram_sdba2 = MX6DL_IOM_DRAM_SDBA2, + .mmdc_dram_sdcke0 = MX6DL_IOM_DRAM_SDCKE0, + .mmdc_dram_sdcke1 = MX6DL_IOM_DRAM_SDCKE1, + .mmdc_dram_sdodt0 = MX6DL_IOM_DRAM_SDODT0, + .mmdc_dram_sdodt1 = MX6DL_IOM_DRAM_SDODT1, + .mmdc_dram_sdqs0 = MX6DL_IOM_DRAM_SDQS0, + .mmdc_dram_sdqs1 = MX6DL_IOM_DRAM_SDQS1, + .mmdc_dram_sdqs2 = MX6DL_IOM_DRAM_SDQS2, + .mmdc_dram_sdqs3 = MX6DL_IOM_DRAM_SDQS3, + .mmdc_dram_sdqs4 = MX6DL_IOM_DRAM_SDQS4, + .mmdc_dram_sdqs5 = MX6DL_IOM_DRAM_SDQS5, + .mmdc_dram_sdqs6 = MX6DL_IOM_DRAM_SDQS6, + .mmdc_dram_sdqs7 = MX6DL_IOM_DRAM_SDQS7, + .mmdc_grp_b0ds = MX6DL_IOM_GRP_B0DS, + .mmdc_grp_b1ds = MX6DL_IOM_GRP_B1DS, + .mmdc_grp_b2ds = MX6DL_IOM_GRP_B2DS, + .mmdc_grp_b3ds = MX6DL_IOM_GRP_B3DS, + .mmdc_grp_b4ds = MX6DL_IOM_GRP_B4DS, + .mmdc_grp_b5ds = MX6DL_IOM_GRP_B5DS, + .mmdc_grp_b6ds = MX6DL_IOM_GRP_B6DS, + .mmdc_grp_b7ds = MX6DL_IOM_GRP_B7DS, + .mmdc_grp_addds = MX6DL_IOM_GRP_ADDDS, + .mmdc_grp_ddrpke = MX6DL_IOM_GRP_DDRPKE, + .mmdc_grp_ctlds = MX6DL_IOM_GRP_CTLDS, + .mmdc_grp_ddr_type = MX6DL_IOM_GRP_DDR_TYPE, + .mmdc_ddrmode_ctl = MX6DL_IOM_DDRMODE_CTL, + .mmdc_grp_ddrmode = MX6Q_IOM_GRP_DDRMODE, +}; +#endif + +struct mx6_mmdc_cfgregs const mx6_ddrcfg = { + .mmdc_p0_mdctl = MX6_MMDC_P0_MDCTL, + .mmdc_p0_mdpdc = MX6_MMDC_P0_MDPDC, + .mmdc_p0_mdotc = MX6_MMDC_P0_MDOTC, + .mmdc_p0_mdcfg0 = MX6_MMDC_P0_MDCFG0, + .mmdc_p0_mdcfg1 = MX6_MMDC_P0_MDCFG1, + .mmdc_p0_mdcfg2 = MX6_MMDC_P0_MDCFG2, + .mmdc_p0_mdmisc = MX6_MMDC_P0_MDMISC, + .mmdc_p0_mdscr = MX6_MMDC_P0_MDSCR, + .mmdc_p0_mdref = MX6_MMDC_P0_MDREF, + .mmdc_p0_mdrwd = MX6_MMDC_P0_MDRWD, + .mmdc_p0_mdor = MX6_MMDC_P0_MDOR, + .mmdc_p0_mdasp = MX6_MMDC_P0_MDASP, + .mmdc_p0_mapsr = MX6_MMDC_P0_MAPSR, + .mmdc_p0_mpzqhwctrl = MX6_MMDC_P0_MPZQHWCTRL, + .mmdc_p0_mpwldectrl0 = MX6_MMDC_P0_MPWLDECTRL0, + .mmdc_p0_mpwldectrl1 = MX6_MMDC_P0_MPWLDECTRL1, + .mmdc_p0_mpodtctrl = MX6_MMDC_P0_MPODTCTRL, + .mmdc_p0_mprddqby0dl = MX6_MMDC_P0_MPRDDQBY0DL, + .mmdc_p0_mprddqby1dl = MX6_MMDC_P0_MPRDDQBY1DL, + .mmdc_p0_mprddqby2dl = MX6_MMDC_P0_MPRDDQBY2DL, + .mmdc_p0_mprddqby3dl = MX6_MMDC_P0_MPRDDQBY3DL, + .mmdc_p0_mpdgctrl0 = MX6_MMDC_P0_MPDGCTRL0, + .mmdc_p0_mpdgctrl1 = MX6_MMDC_P0_MPDGCTRL1, + .mmdc_p0_mprddlctl = MX6_MMDC_P0_MPRDDLCTL, + .mmdc_p0_mpwrdlctl = MX6_MMDC_P0_MPWRDLCTL, + .mmdc_p0_mpmur0 = MX6_MMDC_P0_MPMUR0, + + .mmdc_p1_mdctl = MX6_MMDC_P1_MDCTL, + .mmdc_p1_mdpdc = MX6_MMDC_P1_MDPDC, + .mmdc_p1_mdotc = MX6_MMDC_P1_MDOTC, + .mmdc_p1_mdcfg0 = MX6_MMDC_P1_MDCFG0, + .mmdc_p1_mdcfg1 = MX6_MMDC_P1_MDCFG1, + .mmdc_p1_mdcfg2 = MX6_MMDC_P1_MDCFG2, + .mmdc_p1_mdmisc = MX6_MMDC_P1_MDMISC, + .mmdc_p1_mdscr = MX6_MMDC_P1_MDSCR, + .mmdc_p1_mdref = MX6_MMDC_P1_MDREF, + .mmdc_p1_mdrwd = MX6_MMDC_P1_MDRWD, + .mmdc_p1_mdor = MX6_MMDC_P1_MDOR, + .mmdc_p1_mdasp = MX6_MMDC_P1_MDASP, + .mmdc_p1_mapsr = MX6_MMDC_P1_MAPSR, + .mmdc_p1_mpzqhwctrl = MX6_MMDC_P1_MPZQHWCTRL, + .mmdc_p1_mpwldectrl0 = MX6_MMDC_P1_MPWLDECTRL0, + .mmdc_p1_mpwldectrl1 = MX6_MMDC_P1_MPWLDECTRL1, + .mmdc_p1_mpodtctrl = MX6_MMDC_P1_MPODTCTRL, + .mmdc_p1_mprddqby0dl = MX6_MMDC_P1_MPRDDQBY0DL, + .mmdc_p1_mprddqby1dl = MX6_MMDC_P1_MPRDDQBY1DL, + .mmdc_p1_mprddqby2dl = MX6_MMDC_P1_MPRDDQBY2DL, + .mmdc_p1_mprddqby3dl = MX6_MMDC_P1_MPRDDQBY3DL, + .mmdc_p1_mpdgctrl0 = MX6_MMDC_P1_MPDGCTRL0, + .mmdc_p1_mpdgctrl1 = MX6_MMDC_P1_MPDGCTRL1, + .mmdc_p1_mprddlctl = MX6_MMDC_P1_MPRDDLCTL, + .mmdc_p1_mpwrdlctl = MX6_MMDC_P1_MPWRDLCTL, + .mmdc_p1_mpmur0 = MX6_MMDC_P1_MPMUR0, +}; + +/* + * Configure mmdc iomux with board-specific register set + * and a bus width + */ +void mx6_dram_iocfg(unsigned width, + const struct mx6_mmdc_ioregs *a, + const struct mx6_mmdc_ioregs *d) +{ + /* DDR IO Type */ + writel(d->mmdc_grp_ddr_type, a->mmdc_grp_ddr_type); + writel(d->mmdc_grp_ddrpke, a->mmdc_grp_ddrpke); + + /* Clock */ + writel(d->mmdc_dram_sdclk_0, a->mmdc_dram_sdclk_0); + writel(d->mmdc_dram_sdclk_1, a->mmdc_dram_sdclk_1); + + /* Address */ + writel(d->mmdc_dram_cas, a->mmdc_dram_cas); + writel(d->mmdc_dram_ras, a->mmdc_dram_ras); + writel(d->mmdc_grp_addds, a->mmdc_grp_addds); + + /* Control */ + writel(d->mmdc_dram_reset, a->mmdc_dram_reset); + writel(d->mmdc_dram_sdcke0, a->mmdc_dram_sdcke0); + writel(d->mmdc_dram_sdcke1, a->mmdc_dram_sdcke1); + writel(d->mmdc_dram_sdba2, a->mmdc_dram_sdba2); + writel(d->mmdc_dram_sdodt0, a->mmdc_dram_sdodt0); + writel(d->mmdc_dram_sdodt1, a->mmdc_dram_sdodt1); + writel(d->mmdc_grp_ctlds, a->mmdc_grp_ctlds); + + /* Data Strobes */ + writel(d->mmdc_ddrmode_ctl, a->mmdc_ddrmode_ctl); + writel(d->mmdc_dram_sdqs0, a->mmdc_dram_sdqs0); + writel(d->mmdc_dram_sdqs1, a->mmdc_dram_sdqs1); + if (width >= 32) { + writel(d->mmdc_dram_sdqs2, a->mmdc_dram_sdqs2); + writel(d->mmdc_dram_sdqs3, a->mmdc_dram_sdqs3); + } + if (width >= 64) { + writel(d->mmdc_dram_sdqs4, a->mmdc_dram_sdqs4); + writel(d->mmdc_dram_sdqs5, a->mmdc_dram_sdqs5); + writel(d->mmdc_dram_sdqs6, a->mmdc_dram_sdqs6); + writel(d->mmdc_dram_sdqs7, a->mmdc_dram_sdqs7); + } + + /* Data */ + writel(d->mmdc_grp_ddrmode, a->mmdc_grp_ddrmode); + writel(d->mmdc_grp_b0ds, a->mmdc_grp_b0ds); + writel(d->mmdc_grp_b1ds, a->mmdc_grp_b1ds); + if (width >= 32) { + writel(d->mmdc_grp_b2ds, a->mmdc_grp_b2ds); + writel(d->mmdc_grp_b3ds, a->mmdc_grp_b3ds); + } + if (width >= 64) { + writel(d->mmdc_grp_b4ds, a->mmdc_grp_b4ds); + writel(d->mmdc_grp_b5ds, a->mmdc_grp_b5ds); + writel(d->mmdc_grp_b6ds, a->mmdc_grp_b6ds); + writel(d->mmdc_grp_b7ds, a->mmdc_grp_b7ds); + } + writel(d->mmdc_dram_dqm0, a->mmdc_dram_dqm0); + writel(d->mmdc_dram_dqm1, a->mmdc_dram_dqm1); + if (width >= 32) { + writel(d->mmdc_dram_dqm2, a->mmdc_dram_dqm2); + writel(d->mmdc_dram_dqm3, a->mmdc_dram_dqm3); + } + if (width >= 64) { + writel(d->mmdc_dram_dqm4, a->mmdc_dram_dqm4); + writel(d->mmdc_dram_dqm5, a->mmdc_dram_dqm5); + writel(d->mmdc_dram_dqm6, a->mmdc_dram_dqm6); + writel(d->mmdc_dram_dqm7, a->mmdc_dram_dqm7); + } +} + + +/* configure DDR3 mode registers */ +static inline void write_mr(u16 val, u8 ba, u8 cmd, bool cs1, u32 mdscr) +{ + u32 reg = val << 16; + reg |= (1 << 15); /* Configuration request */ + reg |= (cmd << 4); /* Command */ + reg |= (cs1 << 3); /* CS0 | CS1 */ + reg |= ba; /* mode register addr */ + debug("MR%d: val=%04x ba=%d cmd=%d cs1=%d\n", ba, val, ba, cmd, cs1); + writel(reg, mdscr); +} + +/* + * Configure mx6 mmdc registers based on: + * - board-specific memory configuration + * - board-specific calibration data + * - ddr3 chip details + * + * The various calculations here are derived from the Freescale + * i.Mx6DQSDL DDR3 Script Aid spreadsheet (DOC-94917) designed to generate MMDC + * configuration registers based on memory system and memory chip parameters. + * + * The defaults here are those which were specified in the spreadsheet. + * For details on each register, refer to the IMX6DQRM and/or IMX6SDLRM + */ +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *i, + const struct mx6_mmdc_cfgregs *a, + const struct mx6_mmdc_calibration *c, + const struct mx6_ddr3_cfg *m) +{ + u32 reg; + u8 tcke, tcksrx, tcksre, txpdll, taofpd, taonpd, trrd; + u8 todtlon, taxpd, tanpd, tcwl, txp, tfaw, tcl; + u8 todt_idle_off = 0x4; /* from DDR3 Script Aid spreadsheet */ + u16 trcd, trc, tras, twr, tmrd, trtp, trp, twtr, trfc, txs, txpr; + u16 CS0_END; + u16 tdllk = 0x1ff; /* DLL locking time: 512 cycles (JEDEC DDR3) */ + int clkper; /* clock period in picoseconds */ + int clock; /* clock freq in mHz */ + int cs; + + /* MX6D/MX6Q: 1066 MHz memory clock, clkper = 1.894ns = 1894ps */ + if (is_cpu_type(MXC_CPU_MX6Q)) { + clock = 528; + tcwl = 4; + } + /* MX6S/MX6DL: 800 MHz memory clock, clkper = 2.5ns = 2500ps */ + else { + clock = 400; + tcwl = 3; + } + clkper = (1000*1000)/clock; /* ps */ + todtlon = tcwl; + taxpd = tcwl; + tanpd = tcwl; + tcwl = tcwl; + + switch (m->density) { + case 1: /* 1Gb per chip */ + trfc = DIV_ROUND_UP(110000, clkper) - 1; + txs = DIV_ROUND_UP(120000, clkper) - 1; + break; + case 2: /* 2Gb per chip */ + trfc = DIV_ROUND_UP(160000, clkper) - 1; + txs = DIV_ROUND_UP(170000, clkper) - 1; + break; + case 4: /* 4Gb per chip */ + trfc = DIV_ROUND_UP(260000, clkper) - 1; + txs = DIV_ROUND_UP(270000, clkper) - 1; + break; + case 8: /* 8Gb per chip */ + trfc = DIV_ROUND_UP(350000, clkper) - 1; + txs = DIV_ROUND_UP(360000, clkper) - 1; + break; + default: + /* invalid density */ + printf("invalid chip density\n"); + hang(); + break; + } + txpr = txs; + + switch (m->mem_speed) { + case 800: + txp = DIV_ROUND_UP(MAX(3*clkper, 7500), clkper) - 1; + tcke = DIV_ROUND_UP(MAX(3*clkper, 7500), clkper) - 1; + if (m->pagesz == 1) { + tfaw = DIV_ROUND_UP(40000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 10000), clkper) - 1; + } else { + tfaw = DIV_ROUND_UP(50000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 10000), clkper) - 1; + } + break; + case 1066: + txp = DIV_ROUND_UP(MAX(3*clkper, 7500), clkper) - 1; + tcke = DIV_ROUND_UP(MAX(3*clkper, 5625), clkper) - 1; + if (m->pagesz == 1) { + tfaw = DIV_ROUND_UP(37500, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 7500), clkper) - 1; + } else { + tfaw = DIV_ROUND_UP(50000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 10000), clkper) - 1; + } + break; + case 1333: + txp = DIV_ROUND_UP(MAX(3*clkper, 6000), clkper) - 1; + tcke = DIV_ROUND_UP(MAX(3*clkper, 5625), clkper) - 1; + if (m->pagesz == 1) { + tfaw = DIV_ROUND_UP(30000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 6000), clkper) - 1; + } else { + tfaw = DIV_ROUND_UP(45000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 7500), clkper) - 1; + } + break; + case 1600: + txp = DIV_ROUND_UP(MAX(3*clkper, 6000), clkper) - 1; + tcke = DIV_ROUND_UP(MAX(3*clkper, 5000), clkper) - 1; + if (m->pagesz == 1) { + tfaw = DIV_ROUND_UP(30000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 6000), clkper) - 1; + } else { + tfaw = DIV_ROUND_UP(40000, clkper) - 1; + trrd = DIV_ROUND_UP(MAX(4*clkper, 7500), clkper) - 1; + } + break; + default: + printf("invalid memory speed\n"); + hang(); + break; + } + txpdll = DIV_ROUND_UP(MAX(10*clkper, 24000), clkper) - 1; + tcl = DIV_ROUND_UP(m->trcd, clkper/10) - 3; + tcksre = DIV_ROUND_UP(MAX(5*clkper, 10000), clkper); + tcksrx = tcksre; + taonpd = DIV_ROUND_UP(2000, clkper) - 1; + taofpd = taonpd; + trp = DIV_ROUND_UP(m->trcd, clkper/10) - 1; + trcd = trp; + trc = DIV_ROUND_UP(m->trcmin, clkper/10) - 1; + tras = DIV_ROUND_UP(m->trasmin, clkper/10) - 1; + twr = DIV_ROUND_UP(15000, clkper) - 1; + tmrd = DIV_ROUND_UP(MAX(12*clkper, 15000), clkper) - 1; + twtr = ROUND(MAX(4*clkper, 7500)/clkper, 1) - 1; + trtp = twtr; + CS0_END = ((4*i->cs_density) <= 120) ? (4*i->cs_density)+7 : 127; + debug("density:%d Gb (%d Gb per chip)\n", i->cs_density, m->density); + debug("clock: %dMHz (%d ps)\n", clock, clkper); + debug("memspd:%d\n", m->mem_speed); + debug("tcke=%d\n", tcke); + debug("tcksrx=%d\n", tcksrx); + debug("tcksre=%d\n", tcksre); + debug("taofpd=%d\n", taofpd); + debug("taonpd=%d\n", taonpd); + debug("todtlon=%d\n", todtlon); + debug("tanpd=%d\n", tanpd); + debug("taxpd=%d\n", taxpd); + debug("trfc=%d\n", trfc); + debug("txs=%d\n", txs); + debug("txp=%d\n", txp); + debug("txpdll=%d\n", txpdll); + debug("tfaw=%d\n", tfaw); + debug("tcl=%d\n", tcl); + debug("trcd=%d\n", trcd); + debug("trp=%d\n", trp); + debug("trc=%d\n", trc); + debug("tras=%d\n", tras); + debug("twr=%d\n", twr); + debug("tmrd=%d\n", tmrd); + debug("tcwl=%d\n", tcwl); + debug("tdllk=%d\n", tdllk); + debug("trtp=%d\n", trtp); + debug("twtr=%d\n", twtr); + debug("trrd=%d\n", trrd); + debug("txpr=%d\n", txpr); + debug("CS0_END=%d\n", CS0_END); + debug("ncs=%d\n", i->ncs); + debug("Rtt_wr=%d\n", i->rtt_wr); + debug("Rtt_nom=%d\n", i->rtt_nom); + debug("SRT=%d\n", m->SRT); + debug("tcl=%d\n", tcl); + debug("twr=%d\n", twr); + + /* ZQ: enable both one-time & periodic (1ms) HW ZQ calibration */ + writel(0xa1390003, a->mmdc_p0_mpzqhwctrl); + if (i->dsize > 1) + writel(0xa1390003, a->mmdc_p1_mpzqhwctrl); + + /* + * board-specific configuration: + * These values are determined empirically and vary per board layout + * see: + * appnote, ddr3 spreadsheet + */ + writel(c->mmdc_p0_mpwldectrl0, a->mmdc_p0_mpwldectrl0); + writel(c->mmdc_p0_mpwldectrl1, a->mmdc_p0_mpwldectrl1); + writel(c->mmdc_p0_mpdgctrl0, a->mmdc_p0_mpdgctrl0); + writel(c->mmdc_p0_mpdgctrl1, a->mmdc_p0_mpdgctrl1); + writel(c->mmdc_p0_mprddlctl, a->mmdc_p0_mprddlctl); + writel(c->mmdc_p0_mpwrdlctl, a->mmdc_p0_mpwrdlctl); + if (i->dsize > 1) { + writel(c->mmdc_p1_mpwldectrl0, a->mmdc_p1_mpwldectrl0); + writel(c->mmdc_p1_mpwldectrl1, a->mmdc_p1_mpwldectrl1); + writel(c->mmdc_p1_mpdgctrl0, a->mmdc_p1_mpdgctrl0); + writel(c->mmdc_p1_mpdgctrl1, a->mmdc_p1_mpdgctrl1); + writel(c->mmdc_p1_mprddlctl, a->mmdc_p1_mprddlctl); + writel(c->mmdc_p1_mpwrdlctl, a->mmdc_p1_mpwrdlctl); + } + + /* Read data DQ Byte0-3 delay */ + writel(0x33333333, a->mmdc_p0_mprddqby0dl); + writel(0x33333333, a->mmdc_p0_mprddqby1dl); + if (i->dsize > 0) { + writel(0x33333333, a->mmdc_p0_mprddqby2dl); + writel(0x33333333, a->mmdc_p0_mprddqby3dl); + } + if (i->dsize > 1) { + writel(0x33333333, a->mmdc_p1_mprddqby0dl); + writel(0x33333333, a->mmdc_p1_mprddqby1dl); + writel(0x33333333, a->mmdc_p1_mprddqby2dl); + writel(0x33333333, a->mmdc_p1_mprddqby3dl); + } + + /* complete calibration by forced measurement */ + writel(0x00000800, a->mmdc_p0_mpmur0); + if (i->dsize > 1) + writel(0x00000800, a->mmdc_p1_mpmur0); + + /* MMDC init */ + reg = (tcke << 16) | (tcksrx << 3) | tcksre; + writel(reg, a->mmdc_p0_mdpdc); + reg = (taofpd << 27) | (taonpd << 24) | (tanpd << 20) | (taxpd << 16) | + (todtlon << 12) | (todt_idle_off << 4); + writel(reg, a->mmdc_p0_mdotc); + + /* Timing configuration */ + reg = (trfc << 24) | (txs << 16) | (txp << 13) | (txpdll << 9) | + (tfaw << 4) | tcl; + writel(reg, a->mmdc_p0_mdcfg0); + reg = (trcd << 29) | (trp << 26) | (trc << 21) | (tras << 16) | + (1 << 15) | /* trpa */ + (twr << 9) | (tmrd << 5) | tcwl; + writel(reg, a->mmdc_p0_mdcfg1); + reg = (tdllk << 16) | (trtp << 6) | (twtr << 3) | trrd; + writel(reg, a->mmdc_p0_mdcfg2); + reg = (i->cs1_mirror << 19) | (i->walat << 16) | (i->bi_on << 12) | + (i->mif3_mode << 9) | (i->ralat << 6); + writel(reg, a->mmdc_p0_mdmisc); + + /* configuration request */ + writel(1 << 15, a->mmdc_p0_mdscr); /* config request */ + writel(0x000026d2, a->mmdc_p0_mdrwd); + reg = (txpr << 16) | (i->sde_to_rst << 8) | (i->rst_to_cke << 0); + writel(reg, a->mmdc_p0_mdor); + + /* addressing */ + writel(CS0_END, a->mmdc_p0_mdasp); + reg = (1 << 31) | /* SDE_0 */ + ((i->ncs == 2) ? 1 : 0) << 30 | /* SDE_1 */ + (m->rowaddr - 11) << 24 | /* ROW */ + (m->coladdr - 9) << 20 | /* COL */ + (1 << 19) | /* Burst Length = 8 for DDR3 */ + (i->dsize << 16); /* DDR data bus size */ + writel(reg, a->mmdc_p0_mdctl); + + /* Write Mode Registers to Init DDR3 devices */ + for (cs = 0; cs < i->ncs; cs++) { + /* MR2 */ + reg = (i->rtt_wr & 3) << 9 | (m->SRT & 1) << 7 | + ((tcwl - 3) & 3) << 3; + write_mr(reg, 2, 3, cs, a->mmdc_p0_mdscr); + /* MR3 */ + write_mr(0, 3, 3, cs, a->mmdc_p0_mdscr); + /* MR1 */ + reg = ((i->rtt_nom & 1) ? 1 : 0) << 2 | + ((i->rtt_nom & 2) ? 1 : 0) << 6; + write_mr(reg, 1, 3, cs, a->mmdc_p0_mdscr); + reg = ((tcl - 1) << 4) | /* CAS */ + (1 << 8) | /* DLL Reset */ + ((twr - 3) << 9); /* Write Recovery */ + /* MR0 */ + write_mr(reg, 0, 3, cs, a->mmdc_p0_mdscr); + /* ZQ calibration */ + reg = (1 << 10); + write_mr(reg, 0, 4, cs, a->mmdc_p0_mdscr); + } + + /* refresh control register */ + reg = (1 << 14) | /* REF_SEL: Periodic refresh cycles of 32kHz */ + (7 << 11); /* REFR: Refresh Rate - 8 refreshes */ + writel(reg, a->mmdc_p0_mdref); + + /* MMDC Termination: rtt_nom:2 RZQ/2(120ohm), rtt_nom:1 RZQ/4(60ohm) */ + reg = (i->rtt_nom == 2) ? 0x00011117 : 0x00022227; + writel(reg, a->mmdc_p0_mpodtctrl); + if (i->dsize > 1) + writel(reg, a->mmdc_p1_mpodtctrl); + /* Power down control */ + reg = (tcke & 0x7) << 16 | + 5 << 12 | /* PWDT_1: 256 cycles */ + 5 << 8 | /* PWDT_0: 256 cycles */ + 1 << 6 | /* BOTH_CS_PD */ + (tcksrx & 0x7) << 3 | + (tcksre & 0x7); + writel(reg, a->mmdc_p0_mdpdc); /* SDCTL power down enabled */ + writel(0x00011006, a->mmdc_p0_mapsr); /* ADOPT power down enabled */ + writel(0x00000000, a->mmdc_p0_mdscr); /* init complete */ +} diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 6ac857e..1081aa9 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -9,6 +9,52 @@ #define MX6_ADDR_DECLARE(prefix, name, addr) \ prefix##name = addr
+/* + * MMDC iomux registers (pinctl/padctl) - (different for IMX6DQ vs IMX6SDL) + */ +struct mx6_mmdc_ioregs { + u32 mmdc_dram_dqm0; + u32 mmdc_dram_dqm1; + u32 mmdc_dram_dqm2; + u32 mmdc_dram_dqm3; + u32 mmdc_dram_dqm4; + u32 mmdc_dram_dqm5; + u32 mmdc_dram_dqm6; + u32 mmdc_dram_dqm7; + u32 mmdc_dram_cas; + u32 mmdc_dram_ras; + u32 mmdc_dram_reset; + u32 mmdc_dram_sdclk_0; + u32 mmdc_dram_sdclk_1; + u32 mmdc_dram_sdba2; + u32 mmdc_dram_sdcke0; + u32 mmdc_dram_sdcke1; + u32 mmdc_dram_sdodt0; + u32 mmdc_dram_sdodt1; + u32 mmdc_dram_sdqs0; + u32 mmdc_dram_sdqs1; + u32 mmdc_dram_sdqs2; + u32 mmdc_dram_sdqs3; + u32 mmdc_dram_sdqs4; + u32 mmdc_dram_sdqs5; + u32 mmdc_dram_sdqs6; + u32 mmdc_dram_sdqs7; + u32 mmdc_grp_b0ds; + u32 mmdc_grp_b1ds; + u32 mmdc_grp_b2ds; + u32 mmdc_grp_b3ds; + u32 mmdc_grp_b4ds; + u32 mmdc_grp_b5ds; + u32 mmdc_grp_b6ds; + u32 mmdc_grp_b7ds; + u32 mmdc_grp_addds; + u32 mmdc_grp_ddrmode; + u32 mmdc_ddrmode_ctl; + u32 mmdc_grp_ddrpke; + u32 mmdc_grp_ctlds; + u32 mmdc_grp_ddr_type; +}; + #ifdef CONFIG_MX6QDL enum { #define MX6_ADDR_DECL(name, addr) \ @@ -16,6 +62,7 @@ enum { #include "mx6q-ddr.h" }; #undef MX6_ADDR_DECL +extern struct mx6_mmdc_ioregs const mx6dq_ctrl;
enum { #define MX6_ADDR_DECL(name, addr) \ @@ -23,6 +70,8 @@ enum { #include "mx6dl-ddr.h" };
+extern struct mx6_mmdc_ioregs const mx6sdl_ctrl; + #elif defined(CONFIG_MX6Q) #define MX6_ADDR_DECL(name, addr) \ MX6_ADDR_DECLARE(MX6_, name, addr), @@ -35,6 +84,7 @@ enum { #error "Please select cpu" #endif
+/* channel 0 */ #define MX6_MMDC_P0_MDCTL 0x021b0000 #define MX6_MMDC_P0_MDPDC 0x021b0004 #define MX6_MMDC_P0_MDOTC 0x021b0008 @@ -62,6 +112,7 @@ enum { #define MX6_MMDC_P0_MPWRDLCTL 0x021b0850 #define MX6_MMDC_P0_MPMUR0 0x021b08b8
+/* channel 1 */ #define MX6_MMDC_P1_MDCTL 0x021b4000 #define MX6_MMDC_P1_MDPDC 0x021b4004 #define MX6_MMDC_P1_MDOTC 0x021b4008 @@ -89,4 +140,149 @@ enum { #define MX6_MMDC_P1_MPWRDLCTL 0x021b4850 #define MX6_MMDC_P1_MPMUR0 0x021b48b8
+/* Device Information: + * Varies per DDR3 part number and speed grade + */ +struct mx6_ddr3_cfg { + u16 mem_speed; /* ie 1600 for DDR3-1600 (800,1066,1333,1600) */ + u8 density; /* chip density (Gb) (1,2,4,8) */ + u8 width; /* bus width (bits) (4,8,16) */ + u8 banks; /* number of banks */ + u8 rowaddr; /* row address bits (11-16)*/ + u8 coladdr; /* col address bits (9-12) */ + u8 pagesz; /* page size (K) (1-2) */ + u16 trcd; /* tRCD=tRP=CL (ns*100) */ + u16 trcmin; /* tRC min (ns*100) */ + u16 trasmin; /* tRAS min (ns*100) */ + u8 SRT; /* self-refresh temperature: 0=normal, 1=extended */ +}; + +/* + * System Information: + * Varies per board design, memory layout, and termination choices + */ +struct mx6_ddr_sysinfo { + u8 dsize; /* size of bus (in dwords: 0=16bit,1=32bit,2=64bit) */ + u8 cs_density; /* density per chip select (Gb) */ + u8 ncs; /* number chip selects used (1|2) */ + char cs1_mirror;/* enable address mirror (0|1) */ + char bi_on; /* Bank interleaving enable */ + u8 rtt_nom; /* Rtt_Nom (DDR3_RTT_*) */ + u8 rtt_wr; /* Rtt_Wr (DDR3_RTT_*) */ + u8 ralat; /* Read Additional Latency (0-7) */ + u8 walat; /* Write Additional Latency (0-3) */ + u8 mif3_mode; /* Command prediction working mode */ + u8 rst_to_cke; /* Time from SDE enable to CKE rise */ + u8 sde_to_rst; /* Time from SDE enable until DDR reset# is high */ +}; + +/* + * Board specific calibration: + * This includes write leveling calibration values as well as DQS gating + * and read/write delays. These values are board/layout/device specific. + * Freescale recommends using the i.MX6 DDR Stress Test Tool V1.0.2 + * (DOC-96412) to determine these values over a range of boards and + * temperatures. + */ +struct mx6_mmdc_calibration { + /* write leveling calibration */ + u32 mmdc_p0_mpwldectrl0; + u32 mmdc_p0_mpwldectrl1; + u32 mmdc_p1_mpwldectrl0; + u32 mmdc_p1_mpwldectrl1; + /* read DQS gating */ + u32 mmdc_p0_mpdgctrl0; + u32 mmdc_p0_mpdgctrl1; + u32 mmdc_p1_mpdgctrl0; + u32 mmdc_p1_mpdgctrl1; + /* read delay */ + u32 mmdc_p0_mprddlctl; + u32 mmdc_p1_mprddlctl; + /* write delay */ + u32 mmdc_p0_mpwrdlctl; + u32 mmdc_p1_mpwrdlctl; +}; + +/* + * MMDC Configuration registers (same for IMX6DQ vs IMX6SDL) + */ +struct mx6_mmdc_cfgregs { + /* channel0 */ + u32 mmdc_p0_mdctl; + u32 mmdc_p0_mdpdc; + u32 mmdc_p0_mdotc; + u32 mmdc_p0_mdcfg0; + u32 mmdc_p0_mdcfg1; + u32 mmdc_p0_mdcfg2; + u32 mmdc_p0_mdmisc; + u32 mmdc_p0_mdscr; + u32 mmdc_p0_mdref; + u32 mmdc_p0_mdrwd; + u32 mmdc_p0_mdor; + u32 mmdc_p0_mdasp; + u32 mmdc_p0_mapsr; + u32 mmdc_p0_mpzqhwctrl; + + /* board specific: run write leveling calibration to determine */ + u32 mmdc_p0_mpwldectrl0; + u32 mmdc_p0_mpwldectrl1; + /* board specific: read DQS gating */ + u32 mmdc_p0_mpdgctrl0; + u32 mmdc_p0_mpdgctrl1; + /* board specific: read calibration */ + u32 mmdc_p0_mprddlctl; + /* board specific: write calibration */ + u32 mmdc_p0_mpwrdlctl; + + /* read data bit delay */ + u32 mmdc_p0_mprddqby0dl; + u32 mmdc_p0_mprddqby1dl; + u32 mmdc_p0_mprddqby2dl; + u32 mmdc_p0_mprddqby3dl; + + u32 mmdc_p0_mpodtctrl; + u32 mmdc_p0_mpmur0; + + /* channel1 */ + u32 mmdc_p1_mdctl; + u32 mmdc_p1_mdpdc; + u32 mmdc_p1_mdotc; + u32 mmdc_p1_mdcfg0; + u32 mmdc_p1_mdcfg1; + u32 mmdc_p1_mdcfg2; + u32 mmdc_p1_mdmisc; + u32 mmdc_p1_mdscr; + u32 mmdc_p1_mdref; + u32 mmdc_p1_mdrwd; + u32 mmdc_p1_mdor; + u32 mmdc_p1_mdasp; + u32 mmdc_p1_mapsr; + u32 mmdc_p1_mpzqhwctrl; + u32 mmdc_p1_mpwldectrl0; + u32 mmdc_p1_mpwldectrl1; + u32 mmdc_p1_mpodtctrl; + u32 mmdc_p1_mprddqby0dl; + u32 mmdc_p1_mprddqby1dl; + u32 mmdc_p1_mprddqby2dl; + u32 mmdc_p1_mprddqby3dl; + u32 mmdc_p1_mpdgctrl0; + u32 mmdc_p1_mpdgctrl1; + u32 mmdc_p1_mprddlctl; + u32 mmdc_p1_mpwrdlctl; + u32 mmdc_p1_mpmur0; +}; + +extern struct mx6_mmdc_cfgregs const mx6_ddrcfg; + +/* configure iomux (pinctl/padctl) */ +void mx6_dram_iocfg(unsigned width, + const struct mx6_mmdc_ioregs *, + const struct mx6_mmdc_ioregs *); + +/* configure mx6 mmdc registers */ +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *, + const struct mx6_mmdc_cfgregs *, + const struct mx6_mmdc_calibration *, + const struct mx6_ddr3_cfg *); + #endif /*__ASM_ARCH_MX6_DDR_H__ */

Add new function that can take an array of iomux configs, an index, and a stride to allow a multi-dimentional array of pinmux values to be used to define pinmux values per cpu-type.
This takes a different approach to previously proposed solutions which used multiple arrays of pad lists. The goal is to eliminate having these multiple arrays such as 'mx6q_uart1_pads' and 'mx6dl_uart1_pads' which are almost identical copies of each other except for the MX6Q/MX6DL prefix on the PAD.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/imx-common/iomux-v3.c | 19 +++++++++++++++---- arch/arm/include/asm/imx-common/iomux-v3.h | 5 ++++- 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/arch/arm/imx-common/iomux-v3.c b/arch/arm/imx-common/iomux-v3.c index b59b802..d3e1e30 100644 --- a/arch/arm/imx-common/iomux-v3.c +++ b/arch/arm/imx-common/iomux-v3.c @@ -46,12 +46,23 @@ void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad) #endif }
-void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list, - unsigned count) +/* configures a list of pads within an array of lists */ +void imx_iomux_v3_setup_multiple_pads_array(iomux_v3_cfg_t const *pad_list, + unsigned count, unsigned list, + unsigned stride) { iomux_v3_cfg_t const *p = pad_list; int i;
- for (i = 0; i < count; i++) - imx_iomux_v3_setup_pad(*p++); + p += list; + for (i = 0; i < count; i++) { + imx_iomux_v3_setup_pad(*p); + p += stride; + } +} + +void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list, + unsigned count) +{ + imx_iomux_v3_setup_multiple_pads_array(pad_list, count, 0, 1); } diff --git a/arch/arm/include/asm/imx-common/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h index dec11a1..c8cc45b 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -167,7 +167,10 @@ typedef u64 iomux_v3_cfg_t; #define GPIO_PORTF (5 << GPIO_PORT_SHIFT)
void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad); +void imx_iomux_v3_setup_multiple_pads_array(iomux_v3_cfg_t const *pad_list, + unsigned count, unsigned list, + unsigned stride); void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list, - unsigned count); + unsigned count);
#endif /* __MACH_IOMUX_V3_H__*/

Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
Add new function that can take an array of iomux configs, an index, and a stride to allow a multi-dimentional array of pinmux values to be used to define pinmux values per cpu-type.
This takes a different approach to previously proposed solutions which used multiple arrays of pad lists. The goal is to eliminate having these multiple arrays such as 'mx6q_uart1_pads' and 'mx6dl_uart1_pads' which are almost identical copies of each other except for the MX6Q/MX6DL prefix on the PAD.
I like this approach, but I think you should also define the IOMUX, SETUP_PAD, and SETUP_PADS macros from patch 10 in this file, as they (macros and function) are clearly meant to be used together.
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/imx-common/iomux-v3.c | 19 +++++++++++++++---- arch/arm/include/asm/imx-common/iomux-v3.h | 5 ++++- 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/arch/arm/imx-common/iomux-v3.c b/arch/arm/imx-common/iomux-v3.c index b59b802..d3e1e30 100644 --- a/arch/arm/imx-common/iomux-v3.c +++ b/arch/arm/imx-common/iomux-v3.c @@ -46,12 +46,23 @@ void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad) #endif }
-void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
unsigned count)
+/* configures a list of pads within an array of lists */ +void imx_iomux_v3_setup_multiple_pads_array(iomux_v3_cfg_t const *pad_list,
unsigned count, unsigned list,
{ iomux_v3_cfg_t const *p = pad_list; int i;unsigned stride)
- for (i = 0; i < count; i++)
imx_iomux_v3_setup_pad(*p++);
- p += list;
- for (i = 0; i < count; i++) {
imx_iomux_v3_setup_pad(*p);
p += stride;
- }
+}
+void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
unsigned count)
+{
- imx_iomux_v3_setup_multiple_pads_array(pad_list, count, 0, 1); }
diff --git a/arch/arm/include/asm/imx-common/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h index dec11a1..c8cc45b 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -167,7 +167,10 @@ typedef u64 iomux_v3_cfg_t; #define GPIO_PORTF (5 << GPIO_PORT_SHIFT)
void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad); +void imx_iomux_v3_setup_multiple_pads_array(iomux_v3_cfg_t const *pad_list,
unsigned count, unsigned list,
void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,unsigned stride);
unsigned count);
unsigned count);
The above change is a cleanup and should not be in this patch.
#endif /* __MACH_IOMUX_V3_H__*/

On Wed, Apr 9, 2014 at 7:56 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
Add new function that can take an array of iomux configs, an index, and a stride to allow a multi-dimentional array of pinmux values to be used to define pinmux values per cpu-type.
This takes a different approach to previously proposed solutions which used multiple arrays of pad lists. The goal is to eliminate having these multiple arrays such as 'mx6q_uart1_pads' and 'mx6dl_uart1_pads' which are almost identical copies of each other except for the MX6Q/MX6DL prefix on the PAD.
I like this approach, but I think you should also define the IOMUX, SETUP_PAD, and SETUP_PADS macros from patch 10 in this file, as they (macros and function) are clearly meant to be used together.
I agree with this. Do the macro names IOMUX, SETUP_PAD, SETUP_PADS make sense?
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/imx-common/iomux-v3.c | 19 +++++++++++++++---- arch/arm/include/asm/imx-common/iomux-v3.h | 5 ++++- 2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/arch/arm/imx-common/iomux-v3.c b/arch/arm/imx-common/iomux-v3.c index b59b802..d3e1e30 100644 --- a/arch/arm/imx-common/iomux-v3.c +++ b/arch/arm/imx-common/iomux-v3.c @@ -46,12 +46,23 @@ void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad) #endif }
-void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
unsigned count)
+/* configures a list of pads within an array of lists */ +void imx_iomux_v3_setup_multiple_pads_array(iomux_v3_cfg_t const *pad_list,
unsigned count, unsigned list,
{ iomux_v3_cfg_t const *p = pad_list; int i;unsigned stride)
for (i = 0; i < count; i++)
imx_iomux_v3_setup_pad(*p++);
p += list;
for (i = 0; i < count; i++) {
imx_iomux_v3_setup_pad(*p);
p += stride;
}
+}
+void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
unsigned count)
+{
}imx_iomux_v3_setup_multiple_pads_array(pad_list, count, 0, 1);
diff --git a/arch/arm/include/asm/imx-common/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h index dec11a1..c8cc45b 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -167,7 +167,10 @@ typedef u64 iomux_v3_cfg_t; #define GPIO_PORTF (5 << GPIO_PORT_SHIFT)
void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad); +void imx_iomux_v3_setup_multiple_pads_array(iomux_v3_cfg_t const *pad_list,
unsigned count, unsigned list,
void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,unsigned stride);
unsigned count);
unsigned count);
The above change is a cleanup and should not be in this patch.
If there appears to be general agreement on this approach, I'll submit a new 2-patch series just for this patch and pull it out of my overall series.
Regards,
Tim
#endif /* __MACH_IOMUX_V3_H__*/
-- Regards, Nikita.

On 04/09/2014 06:40 PM, Tim Harvey wrote:
On Wed, Apr 9, 2014 at 7:56 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
Add new function that can take an array of iomux configs, an index, and a stride to allow a multi-dimentional array of pinmux values to be used to define pinmux values per cpu-type.
This takes a different approach to previously proposed solutions which used multiple arrays of pad lists. The goal is to eliminate having these multiple arrays such as 'mx6q_uart1_pads' and 'mx6dl_uart1_pads' which are almost identical copies of each other except for the MX6Q/MX6DL prefix on the PAD.
I like this approach, but I think you should also define the IOMUX, SETUP_PAD, and SETUP_PADS macros from patch 10 in this file, as they (macros and function) are clearly meant to be used together.
I agree with this. Do the macro names IOMUX, SETUP_PAD, SETUP_PADS make sense?
My suggestion would be MX6QDL_DDR_IOMUX, MX6QDL_DDR_SETUP_PADS, and MX6QDL_SETUP_PAD (this last one is not DDR specific).

On Thu, Apr 10, 2014 at 7:41 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
On 04/09/2014 06:40 PM, Tim Harvey wrote:
On Wed, Apr 9, 2014 at 7:56 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
Hi Tim,
On 04/03/2014 09:01 AM, Tim Harvey wrote:
Add new function that can take an array of iomux configs, an index, and a stride to allow a multi-dimentional array of pinmux values to be used to define pinmux values per cpu-type.
This takes a different approach to previously proposed solutions which used multiple arrays of pad lists. The goal is to eliminate having these multiple arrays such as 'mx6q_uart1_pads' and 'mx6dl_uart1_pads' which are almost identical copies of each other except for the MX6Q/MX6DL prefix on the PAD.
I like this approach, but I think you should also define the IOMUX, SETUP_PAD, and SETUP_PADS macros from patch 10 in this file, as they (macros and function) are clearly meant to be used together.
I agree with this. Do the macro names IOMUX, SETUP_PAD, SETUP_PADS make sense?
My suggestion would be MX6QDL_DDR_IOMUX, MX6QDL_DDR_SETUP_PADS, and MX6QDL_SETUP_PAD (this last one is not DDR specific).
-- Regards, Nikita.
Stefano,
You mentioned in another thread you had some remarks about my pinmux proposal here? I'm anxious to post a v2 patch and keep this ball rolling.
Thanks,
Tim

use the new iomux function and a macro to create a multi-dimensional array of iomux values without duplicating the defintions.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- board/gateworks/gw_ventana/gw_ventana.c | 497 ++++++++++++++++++++------------ 1 file changed, 316 insertions(+), 181 deletions(-)
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index 2113740..ebf7e7d 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -40,6 +40,17 @@
DECLARE_GLOBAL_DATA_PTR;
+#define IOMUX(x) (MX6Q_##x), (MX6DL_##x) +#define SETUP_PAD(def) \ +if (is_cpu_type(MXC_CPU_MX6Q)) { \ + imx_iomux_v3_setup_pad(MX6Q_##def); \ +} else { \ + imx_iomux_v3_setup_pad(MX6DL_##def); \ +} +#define SETUP_PADS(x) \ + imx_iomux_v3_setup_multiple_pads_array(x, \ + ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2) + /* GPIO's common to all baseboards */ #define GP_PHY_RST IMX_GPIO_NR(1, 30) #define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22) @@ -94,109 +105,145 @@ int board_type;
/* UART1: Function varies per baseboard */ iomux_v3_cfg_t const uart1_pads[] = { - MX6_PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL), - MX6_PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL), + IOMUX(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX(PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), };
/* UART2: Serial Console */ iomux_v3_cfg_t const uart2_pads[] = { - MX6_PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL), - MX6_PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL), + IOMUX(PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX(PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), };
#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
/* I2C1: GSC */ -struct i2c_pads_info i2c_pad_info0 = { +struct i2c_pads_info mx6q_i2c_pad_info0 = { .scl = { - .i2c_mode = MX6_PAD_EIM_D21__I2C1_SCL | PC, - .gpio_mode = MX6_PAD_EIM_D21__GPIO3_IO21 | PC, + .i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC, + .gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC, .gp = IMX_GPIO_NR(3, 21) }, .sda = { - .i2c_mode = MX6_PAD_EIM_D28__I2C1_SDA | PC, - .gpio_mode = MX6_PAD_EIM_D28__GPIO3_IO28 | PC, + .i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC, + .gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC, + .gp = IMX_GPIO_NR(3, 28) + } +}; +struct i2c_pads_info mx6dl_i2c_pad_info0 = { + .scl = { + .i2c_mode = MX6DL_PAD_EIM_D21__I2C1_SCL | PC, + .gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC, + .gp = IMX_GPIO_NR(3, 21) + }, + .sda = { + .i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC, + .gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC, .gp = IMX_GPIO_NR(3, 28) } };
/* I2C2: PMIC/PCIe Switch/PCIe Clock/Mezz */ -struct i2c_pads_info i2c_pad_info1 = { +struct i2c_pads_info mx6q_i2c_pad_info1 = { + .scl = { + .i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC, + .gpio_mode = MX6Q_PAD_KEY_COL3__GPIO4_IO12 | PC, + .gp = IMX_GPIO_NR(4, 12) + }, + .sda = { + .i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC, + .gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO4_IO13 | PC, + .gp = IMX_GPIO_NR(4, 13) + } +}; +struct i2c_pads_info mx6dl_i2c_pad_info1 = { .scl = { - .i2c_mode = MX6_PAD_KEY_COL3__I2C2_SCL | PC, - .gpio_mode = MX6_PAD_KEY_COL3__GPIO4_IO12 | PC, + .i2c_mode = MX6DL_PAD_KEY_COL3__I2C2_SCL | PC, + .gpio_mode = MX6DL_PAD_KEY_COL3__GPIO4_IO12 | PC, .gp = IMX_GPIO_NR(4, 12) }, .sda = { - .i2c_mode = MX6_PAD_KEY_ROW3__I2C2_SDA | PC, - .gpio_mode = MX6_PAD_KEY_ROW3__GPIO4_IO13 | PC, + .i2c_mode = MX6DL_PAD_KEY_ROW3__I2C2_SDA | PC, + .gpio_mode = MX6DL_PAD_KEY_ROW3__GPIO4_IO13 | PC, .gp = IMX_GPIO_NR(4, 13) } };
/* I2C3: Misc/Expansion */ -struct i2c_pads_info i2c_pad_info2 = { +struct i2c_pads_info mx6q_i2c_pad_info2 = { .scl = { - .i2c_mode = MX6_PAD_GPIO_3__I2C3_SCL | PC, - .gpio_mode = MX6_PAD_GPIO_3__GPIO1_IO03 | PC, + .i2c_mode = MX6Q_PAD_GPIO_3__I2C3_SCL | PC, + .gpio_mode = MX6Q_PAD_GPIO_3__GPIO1_IO03 | PC, .gp = IMX_GPIO_NR(1, 3) }, .sda = { - .i2c_mode = MX6_PAD_GPIO_6__I2C3_SDA | PC, - .gpio_mode = MX6_PAD_GPIO_6__GPIO1_IO06 | PC, + .i2c_mode = MX6Q_PAD_GPIO_6__I2C3_SDA | PC, + .gpio_mode = MX6Q_PAD_GPIO_6__GPIO1_IO06 | PC, + .gp = IMX_GPIO_NR(1, 6) + } +}; +struct i2c_pads_info mx6dl_i2c_pad_info2 = { + .scl = { + .i2c_mode = MX6DL_PAD_GPIO_3__I2C3_SCL | PC, + .gpio_mode = MX6DL_PAD_GPIO_3__GPIO1_IO03 | PC, + .gp = IMX_GPIO_NR(1, 3) + }, + .sda = { + .i2c_mode = MX6DL_PAD_GPIO_6__I2C3_SDA | PC, + .gpio_mode = MX6DL_PAD_GPIO_6__GPIO1_IO06 | PC, .gp = IMX_GPIO_NR(1, 6) } };
/* MMC */ iomux_v3_cfg_t const usdhc3_pads[] = { - MX6_PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL), - MX6_PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL), - MX6_PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL), - MX6_PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL), - MX6_PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL), - MX6_PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL), - MX6_PAD_SD3_DAT5__GPIO7_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL), /* CD */ + IOMUX(PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX(PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX(PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX(PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX(PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX(PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX(PAD_SD3_DAT5__GPIO7_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* CD */ };
/* ENET */ iomux_v3_cfg_t const enet_pads[] = { - MX6_PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_TX_CTL__RGMII_TX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_ENET_REF_CLK__ENET_TX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL), - MX6_PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL), + IOMUX(PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_TX_CTL__RGMII_TX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_ENET_REF_CLK__ENET_TX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX(PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL)), /* PHY nRST */ - MX6_PAD_ENET_TXD0__GPIO1_IO30 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_TXD0__GPIO1_IO30 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
/* NAND */ iomux_v3_cfg_t const nfc_pads[] = { - MX6_PAD_NANDF_CLE__NAND_CLE | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_ALE__NAND_ALE | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_WP_B__NAND_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_RB0__NAND_READY_B | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_CS0__NAND_CE0_B | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_SD4_CMD__NAND_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_SD4_CLK__NAND_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D0__NAND_DATA00 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D1__NAND_DATA01 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D2__NAND_DATA02 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D3__NAND_DATA03 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D4__NAND_DATA04 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D5__NAND_DATA05 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D6__NAND_DATA06 | MUX_PAD_CTRL(NO_PAD_CTRL), - MX6_PAD_NANDF_D7__NAND_DATA07 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_NANDF_CLE__NAND_CLE | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_ALE__NAND_ALE | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_WP_B__NAND_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_RB0__NAND_READY_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_CS0__NAND_CE0_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_SD4_CMD__NAND_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_SD4_CLK__NAND_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D0__NAND_DATA00 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D1__NAND_DATA01 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D2__NAND_DATA02 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D3__NAND_DATA03 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D4__NAND_DATA04 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D5__NAND_DATA05 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D6__NAND_DATA06 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX(PAD_NANDF_D7__NAND_DATA07 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
#ifdef CONFIG_CMD_NAND @@ -205,7 +252,7 @@ static void setup_gpmi_nand(void) struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
/* config gpmi nand iomux */ - imx_iomux_v3_setup_multiple_pads(nfc_pads, ARRAY_SIZE(nfc_pads)); + SETUP_PADS(nfc_pads);
/* config gpmi and bch clock to 100 MHz */ clrsetbits_le32(&mxc_ccm->cs2cdr, @@ -231,7 +278,7 @@ static void setup_gpmi_nand(void)
static void setup_iomux_enet(void) { - imx_iomux_v3_setup_multiple_pads(enet_pads, ARRAY_SIZE(enet_pads)); + SETUP_PADS(enet_pads);
/* toggle PHY_RST# */ gpio_direction_output(GP_PHY_RST, 0); @@ -241,35 +288,34 @@ static void setup_iomux_enet(void)
static void setup_iomux_uart(void) { - imx_iomux_v3_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads)); - imx_iomux_v3_setup_multiple_pads(uart2_pads, ARRAY_SIZE(uart2_pads)); + SETUP_PADS(uart1_pads); + SETUP_PADS(uart2_pads); }
#ifdef CONFIG_USB_EHCI_MX6 iomux_v3_cfg_t const usb_pads[] = { - MX6_PAD_GPIO_1__USB_OTG_ID | MUX_PAD_CTRL(DIO_PAD_CTRL), - MX6_PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(DIO_PAD_CTRL), - MX6_PAD_EIM_D22__GPIO3_IO22 | MUX_PAD_CTRL(DIO_PAD_CTRL), /* OTG PWR */ + IOMUX(PAD_GPIO_1__USB_OTG_ID | MUX_PAD_CTRL(DIO_PAD_CTRL)), + IOMUX(PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(DIO_PAD_CTRL)), + /* OTG PWR */ + IOMUX(PAD_EIM_D22__GPIO3_IO22 | MUX_PAD_CTRL(DIO_PAD_CTRL)), };
int board_ehci_hcd_init(int port) { struct ventana_board_info *info = &ventana_info;
- imx_iomux_v3_setup_multiple_pads(usb_pads, ARRAY_SIZE(usb_pads)); + SETUP_PADS(usb_pads);
/* Reset USB HUB (present on GW54xx/GW53xx) */ switch (info->model[3]) { case '3': /* GW53xx */ - imx_iomux_v3_setup_pad(MX6_PAD_GPIO_9__GPIO1_IO09| - MUX_PAD_CTRL(NO_PAD_CTRL)); + SETUP_PAD(PAD_GPIO_9__GPIO1_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL)); gpio_direction_output(IMX_GPIO_NR(1, 9), 0); mdelay(2); gpio_set_value(IMX_GPIO_NR(1, 9), 1); break; case '4': /* GW54xx */ - imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT0__GPIO1_IO16 | - MUX_PAD_CTRL(NO_PAD_CTRL)); + SETUP_PAD(PAD_SD1_DAT0__GPIO1_IO16 | MUX_PAD_CTRL(NO_PAD_CTRL)); gpio_direction_output(IMX_GPIO_NR(1, 16), 0); mdelay(2); gpio_set_value(IMX_GPIO_NR(1, 16), 1); @@ -301,7 +347,7 @@ int board_mmc_getcd(struct mmc *mmc) int board_mmc_init(bd_t *bis) { /* Only one USDHC controller on Ventana */ - imx_iomux_v3_setup_multiple_pads(usdhc3_pads, ARRAY_SIZE(usdhc3_pads)); + SETUP_PADS(usdhc3_pads); usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); usdhc_cfg.max_bus_width = 4;
@@ -312,17 +358,16 @@ int board_mmc_init(bd_t *bis) #ifdef CONFIG_MXC_SPI iomux_v3_cfg_t const ecspi1_pads[] = { /* SS1 */ - MX6_PAD_EIM_D19__GPIO3_IO19 | MUX_PAD_CTRL(SPI_PAD_CTRL), - MX6_PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL), - MX6_PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL), - MX6_PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL), + IOMUX(PAD_EIM_D19__GPIO3_IO19 | MUX_PAD_CTRL(SPI_PAD_CTRL)), + IOMUX(PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL)), + IOMUX(PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL)), + IOMUX(PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL)), };
static void setup_spi(void) { gpio_direction_output(CONFIG_SF_DEFAULT_CS, 1); - imx_iomux_v3_setup_multiple_pads(ecspi1_pads, - ARRAY_SIZE(ecspi1_pads)); + SETUP_PADS(ecspi1_pads); } #endif
@@ -453,118 +498,118 @@ read_eeprom(void) /* common to add baseboards */ static iomux_v3_cfg_t const gw_gpio_pads[] = { /* MSATA_EN */ - MX6_PAD_SD4_DAT0__GPIO2_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_SD4_DAT0__GPIO2_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* RS232_EN# */ - MX6_PAD_SD4_DAT3__GPIO2_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_SD4_DAT3__GPIO2_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
/* prototype */ static iomux_v3_cfg_t const gwproto_gpio_pads[] = { /* PANLEDG# */ - MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */ - MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* LOCLED# */ - MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* RS485_EN */ - MX6_PAD_SD3_DAT4__GPIO7_IO01 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_SD3_DAT4__GPIO7_IO01 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */ - MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */ - MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_EN */ - MX6_PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* DIOI2C_DIS# */ - MX6_PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCICK_SSON */ - MX6_PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */ - MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
static iomux_v3_cfg_t const gw51xx_gpio_pads[] = { /* PANLEDG# */ - MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */ - MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */ - MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */ - MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
/* GPS_SHDN */ - MX6_PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_PWR */ - MX6_PAD_CSI0_DATA_EN__GPIO5_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_CSI0_DATA_EN__GPIO5_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */ - MX6_PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
static iomux_v3_cfg_t const gw52xx_gpio_pads[] = { /* PANLEDG# */ - MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */ - MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */ - MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */ - MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
/* MX6_LOCLED# */ - MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* GPS_SHDN */ - MX6_PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* USBOTG_SEL */ - MX6_PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_PWR */ - MX6_PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */ - MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
static iomux_v3_cfg_t const gw53xx_gpio_pads[] = { /* PANLEDG# */ - MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */ - MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */ - MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */ - MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
/* MX6_LOCLED# */ - MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* GPS_SHDN */ - MX6_PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_EN */ - MX6_PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */ - MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
static iomux_v3_cfg_t const gw54xx_gpio_pads[] = { /* PANLEDG# */ - MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */ - MX6_PAD_KEY_COL2__GPIO4_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_COL2__GPIO4_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* MX6_LOCLED# */ - MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* MIPI_DIO */ - MX6_PAD_SD1_DAT3__GPIO1_IO21 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_SD1_DAT3__GPIO1_IO21 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* RS485_EN */ - MX6_PAD_EIM_D24__GPIO3_IO24 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_EIM_D24__GPIO3_IO24 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */ - MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */ - MX6_PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* DIOI2C_DIS# */ - MX6_PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* DIOI2C_DIS# */ - MX6_PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCICK_SSON */ - MX6_PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */ - MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL), + IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
/* @@ -572,9 +617,9 @@ static iomux_v3_cfg_t const gw54xx_gpio_pads[] = { * be pinmuxed as a GPIO or in some cases a PWM */ struct dio_cfg { - iomux_v3_cfg_t gpio_padmux; + iomux_v3_cfg_t gpio_padmux[2]; unsigned gpio_param; - iomux_v3_cfg_t pwm_padmux; + iomux_v3_cfg_t pwm_padmux[2]; unsigned pwm_param; };
@@ -601,16 +646,32 @@ struct ventana gpio_cfg[] = { /* GW5400proto */ { .gpio_pads = gw54xx_gpio_pads, - .num_pads = ARRAY_SIZE(gw54xx_gpio_pads), + .num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2, .dio_cfg = { - { MX6_PAD_GPIO_9__GPIO1_IO09, IMX_GPIO_NR(1, 9), - MX6_PAD_GPIO_9__PWM1_OUT, 1 }, - { MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19), - MX6_PAD_SD1_DAT2__PWM2_OUT, 2 }, - { MX6_PAD_SD4_DAT1__GPIO2_IO09, IMX_GPIO_NR(2, 9), - MX6_PAD_SD4_DAT1__PWM3_OUT, 3 }, - { MX6_PAD_SD4_DAT2__GPIO2_IO10, IMX_GPIO_NR(2, 10), - MX6_PAD_SD4_DAT2__PWM4_OUT, 4 }, + { + { IOMUX(PAD_GPIO_9__GPIO1_IO09) }, + IMX_GPIO_NR(1, 9), + { IOMUX(PAD_GPIO_9__PWM1_OUT) }, + 1 + }, + { + { IOMUX(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX(PAD_SD4_DAT1__GPIO2_IO09) }, + IMX_GPIO_NR(2, 9), + { IOMUX(PAD_SD4_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX(PAD_SD4_DAT2__GPIO2_IO10) }, + IMX_GPIO_NR(2, 10), + { IOMUX(PAD_SD4_DAT2__PWM4_OUT) }, + 4 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -628,16 +689,32 @@ struct ventana gpio_cfg[] = { /* GW51xx */ { .gpio_pads = gw51xx_gpio_pads, - .num_pads = ARRAY_SIZE(gw51xx_gpio_pads), + .num_pads = ARRAY_SIZE(gw51xx_gpio_pads)/2, .dio_cfg = { - { MX6_PAD_SD1_DAT0__GPIO1_IO16, IMX_GPIO_NR(1, 16), - 0, 0 }, - { MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19), - MX6_PAD_SD1_DAT2__PWM2_OUT, 2 }, - { MX6_PAD_SD1_DAT1__GPIO1_IO17, IMX_GPIO_NR(1, 17), - MX6_PAD_SD1_DAT1__PWM3_OUT, 3 }, - { MX6_PAD_SD1_CMD__GPIO1_IO18, IMX_GPIO_NR(1, 18), - MX6_PAD_SD1_CMD__PWM4_OUT, 4 }, + { + { IOMUX(PAD_SD1_DAT0__GPIO1_IO16) }, + IMX_GPIO_NR(1, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX(PAD_SD1_DAT1__GPIO1_IO17) }, + IMX_GPIO_NR(1, 17), + { IOMUX(PAD_SD1_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX(PAD_SD1_CMD__GPIO1_IO18) }, + IMX_GPIO_NR(1, 18), + { IOMUX(PAD_SD1_CMD__PWM4_OUT) }, + 4 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -653,16 +730,32 @@ struct ventana gpio_cfg[] = { /* GW52xx */ { .gpio_pads = gw52xx_gpio_pads, - .num_pads = ARRAY_SIZE(gw52xx_gpio_pads), + .num_pads = ARRAY_SIZE(gw52xx_gpio_pads)/2, .dio_cfg = { - { MX6_PAD_SD1_DAT0__GPIO1_IO16, IMX_GPIO_NR(1, 16), - 0, 0 }, - { MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19), - MX6_PAD_SD1_DAT2__PWM2_OUT, 2 }, - { MX6_PAD_SD1_DAT1__GPIO1_IO17, IMX_GPIO_NR(1, 17), - MX6_PAD_SD1_DAT1__PWM3_OUT, 3 }, - { MX6_PAD_SD1_CLK__GPIO1_IO20, IMX_GPIO_NR(1, 20), - 0, 0 }, + { + { IOMUX(PAD_SD1_DAT0__GPIO1_IO16) }, + IMX_GPIO_NR(1, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX(PAD_SD1_DAT1__GPIO1_IO17) }, + IMX_GPIO_NR(1, 17), + { IOMUX(PAD_SD1_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX(PAD_SD1_CLK__GPIO1_IO20) }, + IMX_GPIO_NR(1, 20), + { 0, 0 }, + 0 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -680,16 +773,32 @@ struct ventana gpio_cfg[] = { /* GW53xx */ { .gpio_pads = gw53xx_gpio_pads, - .num_pads = ARRAY_SIZE(gw53xx_gpio_pads), + .num_pads = ARRAY_SIZE(gw53xx_gpio_pads)/2, .dio_cfg = { - { MX6_PAD_SD1_DAT0__GPIO1_IO16, IMX_GPIO_NR(1, 16), - 0, 0 }, - { MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19), - MX6_PAD_SD1_DAT2__PWM2_OUT, 2 }, - { MX6_PAD_SD1_DAT1__GPIO1_IO17, IMX_GPIO_NR(1, 17), - MX6_PAD_SD1_DAT1__PWM3_OUT, 3 }, - { MX6_PAD_SD1_CLK__GPIO1_IO20, IMX_GPIO_NR(1, 20), - 0, 0 }, + { + { IOMUX(PAD_SD1_DAT0__GPIO1_IO16) }, + IMX_GPIO_NR(1, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX(PAD_SD1_DAT1__GPIO1_IO17) }, + IMX_GPIO_NR(1, 17), + { IOMUX(PAD_SD1_DAT1__PWM3_OUT) }, + 3 + }, + { + {IOMUX(PAD_SD1_CLK__GPIO1_IO20) }, + IMX_GPIO_NR(1, 20), + { 0, 0 }, + 0 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -706,16 +815,32 @@ struct ventana gpio_cfg[] = { /* GW54xx */ { .gpio_pads = gw54xx_gpio_pads, - .num_pads = ARRAY_SIZE(gw54xx_gpio_pads), + .num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2, .dio_cfg = { - { MX6_PAD_GPIO_9__GPIO1_IO09, IMX_GPIO_NR(1, 9), - MX6_PAD_GPIO_9__PWM1_OUT, 1 }, - { MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19), - MX6_PAD_SD1_DAT2__PWM2_OUT, 2 }, - { MX6_PAD_SD4_DAT1__GPIO2_IO09, IMX_GPIO_NR(2, 9), - MX6_PAD_SD4_DAT1__PWM3_OUT, 3 }, - { MX6_PAD_SD4_DAT2__GPIO2_IO10, IMX_GPIO_NR(2, 10), - MX6_PAD_SD4_DAT2__PWM4_OUT, 4 }, + { + { IOMUX(PAD_GPIO_9__GPIO1_IO09) }, + IMX_GPIO_NR(1, 9), + { IOMUX(PAD_GPIO_9__PWM1_OUT) }, + 1 + }, + { + { IOMUX(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX(PAD_SD4_DAT1__GPIO2_IO09) }, + IMX_GPIO_NR(2, 9), + { IOMUX(PAD_SD4_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX(PAD_SD4_DAT2__GPIO2_IO10) }, + IMX_GPIO_NR(2, 10), + { IOMUX(PAD_SD4_DAT2__PWM4_OUT) }, + 4 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -805,6 +930,7 @@ static void setup_board_gpio(int board) for (i = 0; i < 4; i++) { struct dio_cfg *cfg = &gpio_cfg[board].dio_cfg[i]; unsigned ctrl = DIO_PAD_CTRL; + unsigned cputype = is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1;
sprintf(arg, "dio%d", i); if (!hwconfig(arg)) @@ -819,14 +945,14 @@ static void setup_board_gpio(int board) cfg->gpio_param%32, cfg->gpio_param); } - imx_iomux_v3_setup_pad(cfg->gpio_padmux | + imx_iomux_v3_setup_pad(cfg->gpio_padmux[cputype] | MUX_PAD_CTRL(ctrl)); gpio_direction_input(cfg->gpio_param); } else if (hwconfig_subarg_cmp("dio2", "mode", "pwm") && cfg->pwm_padmux) { if (!quiet) printf("DIO%d: pwm%d\n", i, cfg->pwm_param); - imx_iomux_v3_setup_pad(cfg->pwm_padmux | + imx_iomux_v3_setup_pad(cfg->pwm_padmux[cputype] | MUX_PAD_CTRL(ctrl)); } } @@ -846,9 +972,10 @@ static void setup_board_gpio(int board) int imx6_pcie_toggle_reset(void) { if (board_type < GW_UNKNOWN) { - gpio_direction_output(gpio_cfg[board_type].pcie_rst, 0); + uint pin = gpio_cfg[board_type].pcie_rst; + gpio_direction_output(pin, 0); mdelay(50); - gpio_direction_output(gpio_cfg[board_type].pcie_rst, 1); + gpio_direction_output(pin, 1); } return 0; } @@ -916,9 +1043,15 @@ int board_init(void) #ifdef CONFIG_MXC_SPI setup_spi(); #endif - setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0); - setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1); - setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2); + if (is_cpu_type(MXC_CPU_MX6Q)) { + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0); + setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info1); + setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info2); + } else { + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0); + setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info1); + setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info2); + }
#ifdef CONFIG_CMD_SATA setup_sata(); @@ -927,11 +1060,13 @@ int board_init(void) board_type = read_eeprom();
/* board-specifc GPIO iomux */ + SETUP_PADS(gw_gpio_pads); if (board_type < GW_UNKNOWN) { - imx_iomux_v3_setup_multiple_pads(gw_gpio_pads, - ARRAY_SIZE(gw_gpio_pads)); - imx_iomux_v3_setup_multiple_pads(gpio_cfg[board_type].gpio_pads, - gpio_cfg[board_type].num_pads); + iomux_v3_cfg_t const *p = gpio_cfg[board_type].gpio_pads; + int count = gpio_cfg[board_type].num_pads; + unsigned cputype = is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1; + + imx_iomux_v3_setup_multiple_pads_array(p, count, cputype, 2); }
return 0;

On 03/04/2014 08:01, Tim Harvey wrote:
use the new iomux function and a macro to create a multi-dimensional array of iomux values without duplicating the defintions.
Signed-off-by: Tim Harvey tharvey@gateworks.com
board/gateworks/gw_ventana/gw_ventana.c | 497 ++++++++++++++++++++------------ 1 file changed, 316 insertions(+), 181 deletions(-)
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index 2113740..ebf7e7d 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -40,6 +40,17 @@
DECLARE_GLOBAL_DATA_PTR;
+#define IOMUX(x) (MX6Q_##x), (MX6DL_##x) +#define SETUP_PAD(def) \ +if (is_cpu_type(MXC_CPU_MX6Q)) { \
- imx_iomux_v3_setup_pad(MX6Q_##def); \
+} else { \
- imx_iomux_v3_setup_pad(MX6DL_##def); \
+}
This macro should be available for other boards, too.
+#define SETUP_PADS(x) \
- imx_iomux_v3_setup_multiple_pads_array(x, \
- ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2)
/* GPIO's common to all baseboards */ #define GP_PHY_RST IMX_GPIO_NR(1, 30) #define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22) @@ -94,109 +105,145 @@ int board_type;
/* UART1: Function varies per baseboard */ iomux_v3_cfg_t const uart1_pads[] = {
- MX6_PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
- MX6_PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
- IOMUX(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
- IOMUX(PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
};
/* UART2: Serial Console */ iomux_v3_cfg_t const uart2_pads[] = {
- MX6_PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
- MX6_PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
- IOMUX(PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
- IOMUX(PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
};
#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
/* I2C1: GSC */ -struct i2c_pads_info i2c_pad_info0 = { +struct i2c_pads_info mx6q_i2c_pad_info0 = { .scl = {
.i2c_mode = MX6_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6_PAD_EIM_D21__GPIO3_IO21 | PC,
.i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC,
What have you changed here ?
.gp = IMX_GPIO_NR(3, 21)
}, .sda = {
.i2c_mode = MX6_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6_PAD_EIM_D28__GPIO3_IO28 | PC,
.i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC,
.gp = IMX_GPIO_NR(3, 28)
- }
+}; +struct i2c_pads_info mx6dl_i2c_pad_info0 = {
- .scl = {
.i2c_mode = MX6DL_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC,
.gp = IMX_GPIO_NR(3, 21)
- },
- .sda = {
.i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC,
.gp = IMX_GPIO_NR(3, 28) }.gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC,
};
/* I2C2: PMIC/PCIe Switch/PCIe Clock/Mezz */ -struct i2c_pads_info i2c_pad_info1 = { +struct i2c_pads_info mx6q_i2c_pad_info1 = {
- .scl = {
.i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6Q_PAD_KEY_COL3__GPIO4_IO12 | PC,
.gp = IMX_GPIO_NR(4, 12)
- },
- .sda = {
.i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO4_IO13 | PC,
.gp = IMX_GPIO_NR(4, 13)
- }
+}; +struct i2c_pads_info mx6dl_i2c_pad_info1 = { .scl = {
.i2c_mode = MX6_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6_PAD_KEY_COL3__GPIO4_IO12 | PC,
.i2c_mode = MX6DL_PAD_KEY_COL3__I2C2_SCL | PC,
.gp = IMX_GPIO_NR(4, 12) }, .sda = {.gpio_mode = MX6DL_PAD_KEY_COL3__GPIO4_IO12 | PC,
.i2c_mode = MX6_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6_PAD_KEY_ROW3__GPIO4_IO13 | PC,
.i2c_mode = MX6DL_PAD_KEY_ROW3__I2C2_SDA | PC,
.gp = IMX_GPIO_NR(4, 13) }.gpio_mode = MX6DL_PAD_KEY_ROW3__GPIO4_IO13 | PC,
};
/* I2C3: Misc/Expansion */ -struct i2c_pads_info i2c_pad_info2 = { +struct i2c_pads_info mx6q_i2c_pad_info2 = { .scl = {
.i2c_mode = MX6_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6_PAD_GPIO_3__GPIO1_IO03 | PC,
.i2c_mode = MX6Q_PAD_GPIO_3__I2C3_SCL | PC,
.gp = IMX_GPIO_NR(1, 3) }, .sda = {.gpio_mode = MX6Q_PAD_GPIO_3__GPIO1_IO03 | PC,
.i2c_mode = MX6_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6_PAD_GPIO_6__GPIO1_IO06 | PC,
.i2c_mode = MX6Q_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6Q_PAD_GPIO_6__GPIO1_IO06 | PC,
.gp = IMX_GPIO_NR(1, 6)
- }
+};
It seems you have already tried but you have not found a solution for this. Anyway, repeating the same structure for all variants looks bad. The solution with SETUP_PADS() and IOMUX is pretty better.
+struct i2c_pads_info mx6dl_i2c_pad_info2 = {
- .scl = {
.i2c_mode = MX6DL_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6DL_PAD_GPIO_3__GPIO1_IO03 | PC,
.gp = IMX_GPIO_NR(1, 3)
- },
- .sda = {
.i2c_mode = MX6DL_PAD_GPIO_6__I2C3_SDA | PC,
.gp = IMX_GPIO_NR(1, 6) }.gpio_mode = MX6DL_PAD_GPIO_6__GPIO1_IO06 | PC,
};
/* MMC */ iomux_v3_cfg_t const usdhc3_pads[] = {
- MX6_PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL),
- MX6_PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
- MX6_PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
- MX6_PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
- MX6_PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
- MX6_PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
- MX6_PAD_SD3_DAT5__GPIO7_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL), /* CD */
- IOMUX(PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
- IOMUX(PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
- IOMUX(PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
- IOMUX(PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
- IOMUX(PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
- IOMUX(PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)),
- IOMUX(PAD_SD3_DAT5__GPIO7_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* CD */
};
/* ENET */ iomux_v3_cfg_t const enet_pads[] = {
- MX6_PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_TX_CTL__RGMII_TX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_ENET_REF_CLK__ENET_TX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL),
- IOMUX(PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_TX_CTL__RGMII_TX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_ENET_REF_CLK__ENET_TX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)),
- IOMUX(PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL)), /* PHY nRST */
- MX6_PAD_ENET_TXD0__GPIO1_IO30 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_TXD0__GPIO1_IO30 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
/* NAND */ iomux_v3_cfg_t const nfc_pads[] = {
- MX6_PAD_NANDF_CLE__NAND_CLE | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_ALE__NAND_ALE | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_WP_B__NAND_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_RB0__NAND_READY_B | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_CS0__NAND_CE0_B | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_SD4_CMD__NAND_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_SD4_CLK__NAND_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D0__NAND_DATA00 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D1__NAND_DATA01 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D2__NAND_DATA02 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D3__NAND_DATA03 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D4__NAND_DATA04 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D5__NAND_DATA05 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D6__NAND_DATA06 | MUX_PAD_CTRL(NO_PAD_CTRL),
- MX6_PAD_NANDF_D7__NAND_DATA07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_NANDF_CLE__NAND_CLE | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_ALE__NAND_ALE | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_WP_B__NAND_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_RB0__NAND_READY_B | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_CS0__NAND_CE0_B | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_SD4_CMD__NAND_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_SD4_CLK__NAND_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D0__NAND_DATA00 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D1__NAND_DATA01 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D2__NAND_DATA02 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D3__NAND_DATA03 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D4__NAND_DATA04 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D5__NAND_DATA05 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D6__NAND_DATA06 | MUX_PAD_CTRL(NO_PAD_CTRL)),
- IOMUX(PAD_NANDF_D7__NAND_DATA07 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
#ifdef CONFIG_CMD_NAND @@ -205,7 +252,7 @@ static void setup_gpmi_nand(void) struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
/* config gpmi nand iomux */
- imx_iomux_v3_setup_multiple_pads(nfc_pads, ARRAY_SIZE(nfc_pads));
- SETUP_PADS(nfc_pads);
I will only suggest to use another name for the macro. SETUP_PADS seems too generic and could conflict in future with other SOCs. IMX6_SETUP_PADS ?
/* config gpmi and bch clock to 100 MHz */ clrsetbits_le32(&mxc_ccm->cs2cdr, @@ -231,7 +278,7 @@ static void setup_gpmi_nand(void)
static void setup_iomux_enet(void) {
- imx_iomux_v3_setup_multiple_pads(enet_pads, ARRAY_SIZE(enet_pads));
SETUP_PADS(enet_pads);
/* toggle PHY_RST# */ gpio_direction_output(GP_PHY_RST, 0);
@@ -241,35 +288,34 @@ static void setup_iomux_enet(void)
static void setup_iomux_uart(void) {
- imx_iomux_v3_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads));
- imx_iomux_v3_setup_multiple_pads(uart2_pads, ARRAY_SIZE(uart2_pads));
- SETUP_PADS(uart1_pads);
- SETUP_PADS(uart2_pads);
}
#ifdef CONFIG_USB_EHCI_MX6 iomux_v3_cfg_t const usb_pads[] = {
- MX6_PAD_GPIO_1__USB_OTG_ID | MUX_PAD_CTRL(DIO_PAD_CTRL),
- MX6_PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(DIO_PAD_CTRL),
- MX6_PAD_EIM_D22__GPIO3_IO22 | MUX_PAD_CTRL(DIO_PAD_CTRL), /* OTG PWR */
- IOMUX(PAD_GPIO_1__USB_OTG_ID | MUX_PAD_CTRL(DIO_PAD_CTRL)),
- IOMUX(PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(DIO_PAD_CTRL)),
- /* OTG PWR */
- IOMUX(PAD_EIM_D22__GPIO3_IO22 | MUX_PAD_CTRL(DIO_PAD_CTRL)),
};
int board_ehci_hcd_init(int port) { struct ventana_board_info *info = &ventana_info;
- imx_iomux_v3_setup_multiple_pads(usb_pads, ARRAY_SIZE(usb_pads));
SETUP_PADS(usb_pads);
/* Reset USB HUB (present on GW54xx/GW53xx) */ switch (info->model[3]) { case '3': /* GW53xx */
imx_iomux_v3_setup_pad(MX6_PAD_GPIO_9__GPIO1_IO09|
MUX_PAD_CTRL(NO_PAD_CTRL));
gpio_direction_output(IMX_GPIO_NR(1, 9), 0); mdelay(2); gpio_set_value(IMX_GPIO_NR(1, 9), 1); break; case '4': /* GW54xx */SETUP_PAD(PAD_GPIO_9__GPIO1_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL));
imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT0__GPIO1_IO16 |
MUX_PAD_CTRL(NO_PAD_CTRL));
gpio_direction_output(IMX_GPIO_NR(1, 16), 0); mdelay(2); gpio_set_value(IMX_GPIO_NR(1, 16), 1);SETUP_PAD(PAD_SD1_DAT0__GPIO1_IO16 | MUX_PAD_CTRL(NO_PAD_CTRL));
@@ -301,7 +347,7 @@ int board_mmc_getcd(struct mmc *mmc) int board_mmc_init(bd_t *bis) { /* Only one USDHC controller on Ventana */
- imx_iomux_v3_setup_multiple_pads(usdhc3_pads, ARRAY_SIZE(usdhc3_pads));
- SETUP_PADS(usdhc3_pads); usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); usdhc_cfg.max_bus_width = 4;
@@ -312,17 +358,16 @@ int board_mmc_init(bd_t *bis) #ifdef CONFIG_MXC_SPI iomux_v3_cfg_t const ecspi1_pads[] = { /* SS1 */
- MX6_PAD_EIM_D19__GPIO3_IO19 | MUX_PAD_CTRL(SPI_PAD_CTRL),
- MX6_PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL),
- MX6_PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL),
- MX6_PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL),
- IOMUX(PAD_EIM_D19__GPIO3_IO19 | MUX_PAD_CTRL(SPI_PAD_CTRL)),
- IOMUX(PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL)),
- IOMUX(PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL)),
- IOMUX(PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL)),
};
static void setup_spi(void) { gpio_direction_output(CONFIG_SF_DEFAULT_CS, 1);
- imx_iomux_v3_setup_multiple_pads(ecspi1_pads,
ARRAY_SIZE(ecspi1_pads));
- SETUP_PADS(ecspi1_pads);
} #endif
@@ -453,118 +498,118 @@ read_eeprom(void) /* common to add baseboards */ static iomux_v3_cfg_t const gw_gpio_pads[] = { /* MSATA_EN */
- MX6_PAD_SD4_DAT0__GPIO2_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_SD4_DAT0__GPIO2_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* RS232_EN# */
- MX6_PAD_SD4_DAT3__GPIO2_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_SD4_DAT3__GPIO2_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
/* prototype */ static iomux_v3_cfg_t const gwproto_gpio_pads[] = { /* PANLEDG# */
- MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */
- MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* LOCLED# */
- MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* RS485_EN */
- MX6_PAD_SD3_DAT4__GPIO7_IO01 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_SD3_DAT4__GPIO7_IO01 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */
- MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */
- MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_EN */
- MX6_PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* DIOI2C_DIS# */
- MX6_PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCICK_SSON */
- MX6_PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */
- MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
static iomux_v3_cfg_t const gw51xx_gpio_pads[] = { /* PANLEDG# */
- MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */
- MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */
- MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */
- MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL),
IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
/* GPS_SHDN */
- MX6_PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_PWR */
- MX6_PAD_CSI0_DATA_EN__GPIO5_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_CSI0_DATA_EN__GPIO5_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */
- MX6_PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
static iomux_v3_cfg_t const gw52xx_gpio_pads[] = { /* PANLEDG# */
- MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */
- MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */
- MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */
- MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL),
IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
/* MX6_LOCLED# */
- MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* GPS_SHDN */
- MX6_PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* USBOTG_SEL */
- MX6_PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_PWR */
- MX6_PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */
- MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
static iomux_v3_cfg_t const gw53xx_gpio_pads[] = { /* PANLEDG# */
- MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */
- MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */
- MX6_PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_A19__GPIO2_IO19 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */
- MX6_PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL),
IOMUX(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)),
/* MX6_LOCLED# */
- MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* GPS_SHDN */
- MX6_PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_RXD0__GPIO1_IO27 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* VID_EN */
- MX6_PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_D31__GPIO3_IO31 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */
- MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
static iomux_v3_cfg_t const gw54xx_gpio_pads[] = { /* PANLEDG# */
- MX6_PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_COL0__GPIO4_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PANLEDR# */
- MX6_PAD_KEY_COL2__GPIO4_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_COL2__GPIO4_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* MX6_LOCLED# */
- MX6_PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* MIPI_DIO */
- MX6_PAD_SD1_DAT3__GPIO1_IO21 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_SD1_DAT3__GPIO1_IO21 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* RS485_EN */
- MX6_PAD_EIM_D24__GPIO3_IO24 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_EIM_D24__GPIO3_IO24 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_PWREN# */
- MX6_PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW0__GPIO4_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* IOEXP_IRQ# */
- MX6_PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* DIOI2C_DIS# */
- MX6_PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* DIOI2C_DIS# */
- MX6_PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_GPIO_19__GPIO4_IO05 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCICK_SSON */
- MX6_PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_SD1_CLK__GPIO1_IO20 | MUX_PAD_CTRL(NO_PAD_CTRL)), /* PCI_RST# */
- MX6_PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL),
- IOMUX(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)),
};
/* @@ -572,9 +617,9 @@ static iomux_v3_cfg_t const gw54xx_gpio_pads[] = {
- be pinmuxed as a GPIO or in some cases a PWM
*/ struct dio_cfg {
- iomux_v3_cfg_t gpio_padmux;
- iomux_v3_cfg_t gpio_padmux[2]; unsigned gpio_param;
- iomux_v3_cfg_t pwm_padmux;
- iomux_v3_cfg_t pwm_padmux[2]; unsigned pwm_param;
};
@@ -601,16 +646,32 @@ struct ventana gpio_cfg[] = { /* GW5400proto */ { .gpio_pads = gw54xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw54xx_gpio_pads),
.dio_cfg = {.num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2,
{ MX6_PAD_GPIO_9__GPIO1_IO09, IMX_GPIO_NR(1, 9),
MX6_PAD_GPIO_9__PWM1_OUT, 1 },
{ MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19),
MX6_PAD_SD1_DAT2__PWM2_OUT, 2 },
{ MX6_PAD_SD4_DAT1__GPIO2_IO09, IMX_GPIO_NR(2, 9),
MX6_PAD_SD4_DAT1__PWM3_OUT, 3 },
{ MX6_PAD_SD4_DAT2__GPIO2_IO10, IMX_GPIO_NR(2, 10),
MX6_PAD_SD4_DAT2__PWM4_OUT, 4 },
{
{ IOMUX(PAD_GPIO_9__GPIO1_IO09) },
IMX_GPIO_NR(1, 9),
{ IOMUX(PAD_GPIO_9__PWM1_OUT) },
1
},
{
{ IOMUX(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX(PAD_SD4_DAT1__GPIO2_IO09) },
IMX_GPIO_NR(2, 9),
{ IOMUX(PAD_SD4_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX(PAD_SD4_DAT2__GPIO2_IO10) },
IMX_GPIO_NR(2, 10),
{ IOMUX(PAD_SD4_DAT2__PWM4_OUT) },
4
}, .leds = { IMX_GPIO_NR(4, 6),},
@@ -628,16 +689,32 @@ struct ventana gpio_cfg[] = { /* GW51xx */ { .gpio_pads = gw51xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw51xx_gpio_pads),
.dio_cfg = {.num_pads = ARRAY_SIZE(gw51xx_gpio_pads)/2,
{ MX6_PAD_SD1_DAT0__GPIO1_IO16, IMX_GPIO_NR(1, 16),
0, 0 },
{ MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19),
MX6_PAD_SD1_DAT2__PWM2_OUT, 2 },
{ MX6_PAD_SD1_DAT1__GPIO1_IO17, IMX_GPIO_NR(1, 17),
MX6_PAD_SD1_DAT1__PWM3_OUT, 3 },
{ MX6_PAD_SD1_CMD__GPIO1_IO18, IMX_GPIO_NR(1, 18),
MX6_PAD_SD1_CMD__PWM4_OUT, 4 },
{
{ IOMUX(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX(PAD_SD1_CMD__GPIO1_IO18) },
IMX_GPIO_NR(1, 18),
{ IOMUX(PAD_SD1_CMD__PWM4_OUT) },
4
}, .leds = { IMX_GPIO_NR(4, 6),},
@@ -653,16 +730,32 @@ struct ventana gpio_cfg[] = { /* GW52xx */ { .gpio_pads = gw52xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw52xx_gpio_pads),
.dio_cfg = {.num_pads = ARRAY_SIZE(gw52xx_gpio_pads)/2,
{ MX6_PAD_SD1_DAT0__GPIO1_IO16, IMX_GPIO_NR(1, 16),
0, 0 },
{ MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19),
MX6_PAD_SD1_DAT2__PWM2_OUT, 2 },
{ MX6_PAD_SD1_DAT1__GPIO1_IO17, IMX_GPIO_NR(1, 17),
MX6_PAD_SD1_DAT1__PWM3_OUT, 3 },
{ MX6_PAD_SD1_CLK__GPIO1_IO20, IMX_GPIO_NR(1, 20),
0, 0 },
{
{ IOMUX(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX(PAD_SD1_CLK__GPIO1_IO20) },
IMX_GPIO_NR(1, 20),
{ 0, 0 },
0
}, .leds = { IMX_GPIO_NR(4, 6),},
@@ -680,16 +773,32 @@ struct ventana gpio_cfg[] = { /* GW53xx */ { .gpio_pads = gw53xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw53xx_gpio_pads),
.dio_cfg = {.num_pads = ARRAY_SIZE(gw53xx_gpio_pads)/2,
{ MX6_PAD_SD1_DAT0__GPIO1_IO16, IMX_GPIO_NR(1, 16),
0, 0 },
{ MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19),
MX6_PAD_SD1_DAT2__PWM2_OUT, 2 },
{ MX6_PAD_SD1_DAT1__GPIO1_IO17, IMX_GPIO_NR(1, 17),
MX6_PAD_SD1_DAT1__PWM3_OUT, 3 },
{ MX6_PAD_SD1_CLK__GPIO1_IO20, IMX_GPIO_NR(1, 20),
0, 0 },
{
{ IOMUX(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{IOMUX(PAD_SD1_CLK__GPIO1_IO20) },
IMX_GPIO_NR(1, 20),
{ 0, 0 },
0
}, .leds = { IMX_GPIO_NR(4, 6),},
@@ -706,16 +815,32 @@ struct ventana gpio_cfg[] = { /* GW54xx */ { .gpio_pads = gw54xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw54xx_gpio_pads),
.dio_cfg = {.num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2,
{ MX6_PAD_GPIO_9__GPIO1_IO09, IMX_GPIO_NR(1, 9),
MX6_PAD_GPIO_9__PWM1_OUT, 1 },
{ MX6_PAD_SD1_DAT2__GPIO1_IO19, IMX_GPIO_NR(1, 19),
MX6_PAD_SD1_DAT2__PWM2_OUT, 2 },
{ MX6_PAD_SD4_DAT1__GPIO2_IO09, IMX_GPIO_NR(2, 9),
MX6_PAD_SD4_DAT1__PWM3_OUT, 3 },
{ MX6_PAD_SD4_DAT2__GPIO2_IO10, IMX_GPIO_NR(2, 10),
MX6_PAD_SD4_DAT2__PWM4_OUT, 4 },
{
{ IOMUX(PAD_GPIO_9__GPIO1_IO09) },
IMX_GPIO_NR(1, 9),
{ IOMUX(PAD_GPIO_9__PWM1_OUT) },
1
},
{
{ IOMUX(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX(PAD_SD4_DAT1__GPIO2_IO09) },
IMX_GPIO_NR(2, 9),
{ IOMUX(PAD_SD4_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX(PAD_SD4_DAT2__GPIO2_IO10) },
IMX_GPIO_NR(2, 10),
{ IOMUX(PAD_SD4_DAT2__PWM4_OUT) },
4
}, .leds = { IMX_GPIO_NR(4, 6),},
@@ -805,6 +930,7 @@ static void setup_board_gpio(int board) for (i = 0; i < 4; i++) { struct dio_cfg *cfg = &gpio_cfg[board].dio_cfg[i]; unsigned ctrl = DIO_PAD_CTRL;
unsigned cputype = is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1;
sprintf(arg, "dio%d", i); if (!hwconfig(arg))
@@ -819,14 +945,14 @@ static void setup_board_gpio(int board) cfg->gpio_param%32, cfg->gpio_param); }
imx_iomux_v3_setup_pad(cfg->gpio_padmux |
} else if (hwconfig_subarg_cmp("dio2", "mode", "pwm") && cfg->pwm_padmux) { if (!quiet) printf("DIO%d: pwm%d\n", i, cfg->pwm_param);imx_iomux_v3_setup_pad(cfg->gpio_padmux[cputype] | MUX_PAD_CTRL(ctrl)); gpio_direction_input(cfg->gpio_param);
imx_iomux_v3_setup_pad(cfg->pwm_padmux |
} }imx_iomux_v3_setup_pad(cfg->pwm_padmux[cputype] | MUX_PAD_CTRL(ctrl));
@@ -846,9 +972,10 @@ static void setup_board_gpio(int board) int imx6_pcie_toggle_reset(void) { if (board_type < GW_UNKNOWN) {
gpio_direction_output(gpio_cfg[board_type].pcie_rst, 0);
uint pin = gpio_cfg[board_type].pcie_rst;
mdelay(50);gpio_direction_output(pin, 0);
gpio_direction_output(gpio_cfg[board_type].pcie_rst, 1);
} return 0;gpio_direction_output(pin, 1);
} @@ -916,9 +1043,15 @@ int board_init(void) #ifdef CONFIG_MXC_SPI setup_spi(); #endif
- setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0);
- setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
- setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2);
- if (is_cpu_type(MXC_CPU_MX6Q)) {
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0);
setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info1);
setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info2);
- } else {
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0);
setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info1);
setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info2);
- }
#ifdef CONFIG_CMD_SATA setup_sata(); @@ -927,11 +1060,13 @@ int board_init(void) board_type = read_eeprom();
/* board-specifc GPIO iomux */
- SETUP_PADS(gw_gpio_pads); if (board_type < GW_UNKNOWN) {
imx_iomux_v3_setup_multiple_pads(gw_gpio_pads,
ARRAY_SIZE(gw_gpio_pads));
imx_iomux_v3_setup_multiple_pads(gpio_cfg[board_type].gpio_pads,
gpio_cfg[board_type].num_pads);
iomux_v3_cfg_t const *p = gpio_cfg[board_type].gpio_pads;
int count = gpio_cfg[board_type].num_pads;
unsigned cputype = is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1;
imx_iomux_v3_setup_multiple_pads_array(p, count, cputype, 2);
}
return 0;
Best regards, Stefano Babic

On Wed, Apr 23, 2014 at 10:31 AM, Stefano Babic sbabic@denx.de wrote:
On 03/04/2014 08:01, Tim Harvey wrote:
use the new iomux function and a macro to create a multi-dimensional array of iomux values without duplicating the defintions.
Signed-off-by: Tim Harvey tharvey@gateworks.com
board/gateworks/gw_ventana/gw_ventana.c | 497 ++++++++++++++++++++------------ 1 file changed, 316 insertions(+), 181 deletions(-)
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index 2113740..ebf7e7d 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -40,6 +40,17 @@
DECLARE_GLOBAL_DATA_PTR;
+#define IOMUX(x) (MX6Q_##x), (MX6DL_##x) +#define SETUP_PAD(def) \ +if (is_cpu_type(MXC_CPU_MX6Q)) { \
imx_iomux_v3_setup_pad(MX6Q_##def); \
+} else { \
imx_iomux_v3_setup_pad(MX6DL_##def); \
+}
This macro should be available for other boards, too.
Yes - I'm moving these macros to iomux-v3.h
+#define SETUP_PADS(x) \
imx_iomux_v3_setup_multiple_pads_array(x, \
ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2)
/* GPIO's common to all baseboards */ #define GP_PHY_RST IMX_GPIO_NR(1, 30) #define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22) @@ -94,109 +105,145 @@ int board_type;
/* UART1: Function varies per baseboard */ iomux_v3_cfg_t const uart1_pads[] = {
MX6_PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
MX6_PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
IOMUX(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
IOMUX(PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
};
/* UART2: Serial Console */ iomux_v3_cfg_t const uart2_pads[] = {
MX6_PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
MX6_PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL),
IOMUX(PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
IOMUX(PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
};
#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
/* I2C1: GSC */ -struct i2c_pads_info i2c_pad_info0 = { +struct i2c_pads_info mx6q_i2c_pad_info0 = { .scl = {
.i2c_mode = MX6_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6_PAD_EIM_D21__GPIO3_IO21 | PC,
.i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC,
What have you changed here ?
I don't have a solution for a pretty macro that avoids duplicating struct i2c_pads_info so I'm creating two versions of the struct; one with MX6Q_* and the other (below) for imx6dl/solo with MX6DL_*
.gp = IMX_GPIO_NR(3, 21) }, .sda = {
.i2c_mode = MX6_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6_PAD_EIM_D28__GPIO3_IO28 | PC,
.i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC,
.gp = IMX_GPIO_NR(3, 28)
}
+}; +struct i2c_pads_info mx6dl_i2c_pad_info0 = {
.scl = {
.i2c_mode = MX6DL_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC,
.gp = IMX_GPIO_NR(3, 21)
},
.sda = {
.i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC, .gp = IMX_GPIO_NR(3, 28) }
};
/* I2C2: PMIC/PCIe Switch/PCIe Clock/Mezz */ -struct i2c_pads_info i2c_pad_info1 = { +struct i2c_pads_info mx6q_i2c_pad_info1 = {
.scl = {
.i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6Q_PAD_KEY_COL3__GPIO4_IO12 | PC,
.gp = IMX_GPIO_NR(4, 12)
},
.sda = {
.i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO4_IO13 | PC,
.gp = IMX_GPIO_NR(4, 13)
}
+}; +struct i2c_pads_info mx6dl_i2c_pad_info1 = { .scl = {
.i2c_mode = MX6_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6_PAD_KEY_COL3__GPIO4_IO12 | PC,
.i2c_mode = MX6DL_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6DL_PAD_KEY_COL3__GPIO4_IO12 | PC, .gp = IMX_GPIO_NR(4, 12) }, .sda = {
.i2c_mode = MX6_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6_PAD_KEY_ROW3__GPIO4_IO13 | PC,
.i2c_mode = MX6DL_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6DL_PAD_KEY_ROW3__GPIO4_IO13 | PC, .gp = IMX_GPIO_NR(4, 13) }
};
/* I2C3: Misc/Expansion */ -struct i2c_pads_info i2c_pad_info2 = { +struct i2c_pads_info mx6q_i2c_pad_info2 = { .scl = {
.i2c_mode = MX6_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6_PAD_GPIO_3__GPIO1_IO03 | PC,
.i2c_mode = MX6Q_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6Q_PAD_GPIO_3__GPIO1_IO03 | PC, .gp = IMX_GPIO_NR(1, 3) }, .sda = {
.i2c_mode = MX6_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6_PAD_GPIO_6__GPIO1_IO06 | PC,
.i2c_mode = MX6Q_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6Q_PAD_GPIO_6__GPIO1_IO06 | PC,
.gp = IMX_GPIO_NR(1, 6)
}
+};
It seems you have already tried but you have not found a solution for this. Anyway, repeating the same structure for all variants looks bad. The solution with SETUP_PADS() and IOMUX is pretty better.
No, I haven't found a pretty solution for dealing with 2 values of struct i2c_pads_info to pass to imx's setup_i2c. I can try to create a new setup_i2c_array and macro similar to what I did for imx_iomux_v3_setup_multiple_pads, or we can leave that to a future patch in case anyone has any better ideas?
+struct i2c_pads_info mx6dl_i2c_pad_info2 = {
.scl = {
.i2c_mode = MX6DL_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6DL_PAD_GPIO_3__GPIO1_IO03 | PC,
.gp = IMX_GPIO_NR(1, 3)
},
.sda = {
.i2c_mode = MX6DL_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6DL_PAD_GPIO_6__GPIO1_IO06 | PC, .gp = IMX_GPIO_NR(1, 6) }
};
<snip>
#ifdef CONFIG_CMD_NAND @@ -205,7 +252,7 @@ static void setup_gpmi_nand(void) struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
/* config gpmi nand iomux */
imx_iomux_v3_setup_multiple_pads(nfc_pads, ARRAY_SIZE(nfc_pads));
SETUP_PADS(nfc_pads);
I will only suggest to use another name for the macro. SETUP_PADS seems too generic and could conflict in future with other SOCs. IMX6_SETUP_PADS ?
My thought is to move this to iomux-v3.h where IOMUX_PAD and NEW_PAD_CTRL macro's are defined. Those are short and not SoC specific because only boards using imx iomux-v3 would include these. My preference is to try and keep the macro name very short otherwise we have to use a lot of line breaks for existing code that fits a pad name and mux control within 80 lines.
How about the following in iomux-v3.h:
/* define a set of pads for IMX6Q/IMX6DUAL and IMX6DL/IMX6SOLO */ IOMUX_PADS(x) /* setup cpu specific pad based on struct declared using IOMUX_PADS(...) */ SETUP_IOMUX_PAD(def) /* setup multiple cpu specific pads based on struct declared using IOMUX_PADS(...) */ SETUP_IOMUX_PADS(def)
Regards,
Tim

Switch to an SPL image. The SPL for Ventana does the following: - setup i2c and read the factory programmed EEPROM to obtain DRAM config and model for board-specific calibration data - configure DRAM per CPU/size/layout/devices/calibration - load u-boot.img from NAND and jump to it
This allows for a single SPL+u-boot.img to replace the previous multiple board configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- board/gateworks/gw_ventana/Makefile | 2 +- board/gateworks/gw_ventana/README | 91 +++--- board/gateworks/gw_ventana/gw_ventana.c | 5 +- board/gateworks/gw_ventana/gw_ventana.cfg | 15 - board/gateworks/gw_ventana/gw_ventana_spl.c | 394 ++++++++++++++++++++++++++ board/gateworks/gw_ventana/gw_ventana_spl.cfg | 29 ++ boards.cfg | 6 +- include/config/uboot.release | 1 + include/configs/gw_ventana.h | 13 +- 9 files changed, 500 insertions(+), 56 deletions(-) create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.c create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.cfg create mode 100644 include/config/uboot.release
diff --git a/board/gateworks/gw_ventana/Makefile b/board/gateworks/gw_ventana/Makefile index e8dab89..8b239ae 100644 --- a/board/gateworks/gw_ventana/Makefile +++ b/board/gateworks/gw_ventana/Makefile @@ -6,5 +6,5 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y := gw_ventana.o gsc.o +obj-y := gw_ventana.o gsc.o gw_ventana_spl.o
diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README index 9e697d6..c45d4b8 100644 --- a/board/gateworks/gw_ventana/README +++ b/board/gateworks/gw_ventana/README @@ -3,53 +3,80 @@ U-Boot for the Gateworks Ventana Product Family boards This file contains information for the port of U-Boot to the Gateworks Ventana Product family boards.
-1. Boot source, boot from NAND +1. Secondary Program Loader (SPL) +--------------------------------- + +The i.MX6 has a BOOT ROM PPL (Primary Program Loader) which supports loading +an executable image from various boot devices. + +The Gateworks Ventana board config uses an SPL build configuration. This +will build the following artifacts from u-boot source: + - SPL - Secondary Program Loader that the i.MX6 BOOT ROM (Primary Program + Loader) boots. This detects CPU/DRAM configuration, configures + The DRAM controller, loads u-boot.img from the detected boot device, + and jumps to it. As this is booted from the PPL, it has an IVT/DCD + table. + - u-boot.img - The main u-boot core which is u-boot.bin with a image header. + + +2. Build +-------- + +To build U-Boot for the Gateworks Ventana product family: + + make gwventana_config + make + + +3. Boot source, boot from NAND ------------------------------
The i.MX6 BOOT ROM expects some structures that provide details of NAND layout and bad block information (referred to as 'bootstreams') which are replicated -multiple times in NAND. The number of replications is configurable through -board strapping options and eFUSE settings. The Freescale 'kobs-ng' -application from the Freescale LTIB BSP, which runs under Linux, must be used -to program the bootstream in order to setup the replicated headers correctly. +multiple times in NAND. The number of replications and their spacing (referred +to as search stride) is configurable through board strapping options and/or +eFUSE settings (BOOT_SEARCH_COUNT / Pages in block from BOOT_CFG2). In +addition, the i.MX6 BOOT ROM Flash Configuration Block (FCB) supports two +copies of a bootloader in flash in the case that a bad block has corrupted one. The Freescale 'kobs-ng' application from the Freescale LTIB BSP, which runs +under Linux and operates on an MTD partition, must be used to program the +bootstream in order to setup this flash structure correctly.
The Gateworks Ventana boards with NAND flash have been factory programmed such that their eFUSE settings expect 2 copies of the boostream (this is specified by providing kobs-ng with the --search_exponent=1 argument). Once in -Linux with MTD support for the NAND on /dev/mtd0 you can program the boostream +Linux with MTD support for the NAND on /dev/mtd0 you can program the SPL with:
-kobs-ng init -v -x --search_exponent=1 u-boot.imx +kobs-ng init -v -x --search_exponent=1 SPL
-The kobs-ng application uses an imximage (u-boot.imx) which contains the -Image Vector Table (IVT) and Device Configuration Data (DCD) structures that -the i.MX6 BOOT ROM requires to boot. The kobs-ng adds the Firmware -Configuration Block (FCB) and Discovered Bad Block Table (DBBT). +The kobs-ng application uses an imximage which contains the Image Vector Table +(IVT) and Device Configuration Data (DCD) structures that the i.MX6 BOOT ROM +requires to boot. The kobs-ng adds the Firmware Configuration Block (FCB) and +Discovered Bad Block Table (DBBT). The SPL build artifact from u-boot is +an imximage.
-This information is taken from: - http://trac.gateworks.com/wiki/ventana/bootloader#NANDFLASH +The u-boot.img, which is the non SPL u-boot binary appended to a u-boot image +header must be programmed in the NAND flash boot device at an offset hard +coded in the SPL. For the Ventana boards, this has been chosen to be 14MB. +The image can be programmed from either u-boot or Linux:
-More details about the i.MX6 BOOT ROM can be found in the IMX6 reference manual. - -2. Build --------- +u-boot: +Ventana > setenv mtdparts mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs) +Ventana > tftp ${loadaddr} u-boot.img && nand erase.part uboot && \ + nand write ${loadaddr} uboot ${filesize}
-There are several Gateworks Ventana boards that share a simliar design but -vary based on CPU, Memory configuration, and subloaded devices. Although -the subloaded devices are handled dynamically in the bootloader using -factory configured EEPROM data to modify the device-tree, the CPU choice -(IMX6Q vs IMX6DL) and memory configurations are currently compile-time -options. +Linux: +nandwrite /dev/mtd1 u-boot.img
-The following Gateworks Ventana configurations exist: - gwventanaq1gspi: MX6Q,1GB,SPI FLASH - gwventanaq : MX6Q,512MB,NAND FLASH - gwventanaq1g : MX6Q,1GB,NAND FLASH - gwventanadl : MX6DL,512MB,NAND FLASH - gwventanadl1g : MX6DL,1GB,NAND FLASH +The above assumes the default Ventana partitioning scheme which is configured +via the mtdparts env var: + - spl: 14MB + - uboot: 2M + - env: 1M + - rootfs: the rest
-To build U-Boot for the MX6Q,1GB,NAND FLASH for example: +This information is taken from: + http://trac.gateworks.com/wiki/ventana/bootloader#NANDFLASH
- make gwventanaq1g_config - make +More details about the i.MX6 BOOT ROM can be found in the IMX6 reference manual.
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index ebf7e7d..7508141 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -1019,8 +1019,9 @@ int board_early_init_f(void)
int dram_init(void) { - gd->ram_size = get_ram_size((void *)PHYS_SDRAM, - CONFIG_DDR_MB*1024*1024); + struct mx6_spl_data *data = (struct mx6_spl_data *) + ((CONFIG_SPL_TEXT_BASE - sizeof(struct mx6_spl_data)) & ~0xf); + gd->ram_size = data->mem_dram_size;
return 0; } diff --git a/board/gateworks/gw_ventana/gw_ventana.cfg b/board/gateworks/gw_ventana/gw_ventana.cfg index 27f0974..9ab95f5 100644 --- a/board/gateworks/gw_ventana/gw_ventana.cfg +++ b/board/gateworks/gw_ventana/gw_ventana.cfg @@ -24,21 +24,6 @@ BOOT_FROM nand
#define __ASSEMBLY__ #include <config.h> -#include "asm/arch/mx6-ddr.h" #include "asm/arch/iomux.h" #include "asm/arch/crm_regs.h" - -/* Memory configuration (size is overridden via eeprom config) */ -#include "../../boundary/nitrogen6x/ddr-setup.cfg" -#if defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 1024 - #include "../../boundary/nitrogen6x/1066mhz_4x128mx16.cfg" -#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 1024 - #include "../../boundary/nitrogen6x/800mhz_4x128mx16.cfg" -#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 512 - #include "../../boundary/nitrogen6x/800mhz_2x128mx16.cfg" -#elif defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 512 - #include "../../boundary/nitrogen6x/800mhz_2x128mx16.cfg" -#else - #error "Unsupported CPU/Memory configuration" -#endif #include "clocks.cfg" diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.c b/board/gateworks/gw_ventana/gw_ventana_spl.c new file mode 100644 index 0000000..492c814 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -0,0 +1,394 @@ +/* + * Author: Tim Harvey tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/mx6_ddr_regs.h> +#include <asm/arch/mx6-ddr.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/sys_proto.h> +#include <asm/imx-common/boot_mode.h> +#include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> +#ifdef CONFIG_SPL +#include <spl.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_SPL_BUILD) + +#define RTT_NOM_120OHM /* use 120ohm Rtt_nom vs 60ohm (lower power) */ +#define I2C_GSC 0 +#define GSC_EEPROM_ADDR 0x51 +#define GSC_EEPROM_DDR_SIZE 0x2B /* enum (512,1024,2048) MB */ +#define GSC_EEPROM_DDR_WIDTH 0x2D /* enum (32,64) bit */ +#define I2C_PAD_CTRL (PAD_CTL_PUS_100K_UP | \ + PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \ + PAD_CTL_ODE | PAD_CTL_SRE_FAST) +#define PC MUX_PAD_CTRL(I2C_PAD_CTRL) +#define CONFIG_SYS_I2C_SPEED 100000 + +/* I2C1: GSC */ +static struct i2c_pads_info mx6q_i2c_pad_info0 = { + .scl = { + .i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC, + .gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC, + .gp = IMX_GPIO_NR(3, 21) + }, + .sda = { + .i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC, + .gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC, + .gp = IMX_GPIO_NR(3, 28) + } +}; +static struct i2c_pads_info mx6dl_i2c_pad_info0 = { + .scl = { + .i2c_mode = MX6DL_PAD_EIM_D21__I2C1_SCL | PC, + .gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC, + .gp = IMX_GPIO_NR(3, 21) + }, + .sda = { + .i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC, + .gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC, + .gp = IMX_GPIO_NR(3, 28) + } +}; + +static void i2c_setup_iomux(void) +{ + if (is_cpu_type(MXC_CPU_MX6Q)) + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0); + else + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0); +} + +static u16 +read_eeprom(void) +{ + u8 data[3]; + + /* + * On a board with a missing/depleted backup battery for GSC, the + * board may be ready to probe the GSC before its firmware is + * running. We will wait here indefinately for the GSC/EEPROM. + */ + while (1) { + if (0 == i2c_set_bus_num(I2C_GSC) && + 0 == i2c_probe(GSC_EEPROM_ADDR)) + break; + /* TODO: mdelay hangs at this point + mdelay(1); + */ + } + + i2c_read(GSC_EEPROM_ADDR, GSC_EEPROM_DDR_SIZE, 1, data, 3); + + return (data[0] << 8) | data[2]; +} + +/* configure mx6 mmdc io registers */ +struct mx6_mmdc_ioregs mmdc_ioregs = { + /* DDR3 */ + .mmdc_grp_ddr_type = 0x000c0000, + /* disable DDR pullups */ + .mmdc_grp_ddrpke = 0x00000000, + /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ + .mmdc_dram_sdclk_0 = 0x00020030, + .mmdc_dram_sdclk_1 = 0x00020030, + .mmdc_dram_cas = 0x00020030, + .mmdc_dram_ras = 0x00020030, + .mmdc_dram_reset = 0x00020030, + /* ADDR[00:16], SDBA[0:1]: 40 ohm */ + .mmdc_grp_addds = 0x00000030, + /* SDCKE[0:1]: 100k pull-up */ + .mmdc_dram_sdcke0 = 0x00003000, + .mmdc_dram_sdcke1 = 0x00003000, + /* SDBA2: pull-up disabled */ + .mmdc_dram_sdba2 = 0x00000000, + /* SDODT[0:1]: 100k pull-up, 40 ohm */ + .mmdc_dram_sdodt0 = 0x00003030, + .mmdc_dram_sdodt1 = 0x00003030, + /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ + .mmdc_grp_ctlds = 0x00000030, + /* SDQS[0:7]: Differential input, 40 ohm */ + .mmdc_ddrmode_ctl = 0x00020000, + .mmdc_dram_sdqs0 = 0x00000030, + .mmdc_dram_sdqs1 = 0x00000030, + .mmdc_dram_sdqs2 = 0x00000030, + .mmdc_dram_sdqs3 = 0x00000030, + .mmdc_dram_sdqs4 = 0x00000030, + .mmdc_dram_sdqs5 = 0x00000030, + .mmdc_dram_sdqs6 = 0x00000030, + .mmdc_dram_sdqs7 = 0x00000030, + + /* DATA[00:63]: Differential input, 40 ohm */ + .mmdc_grp_ddrmode = 0x00020000, + .mmdc_grp_b0ds = 0x00000030, + .mmdc_grp_b1ds = 0x00000030, + .mmdc_grp_b2ds = 0x00000030, + .mmdc_grp_b3ds = 0x00000030, + .mmdc_grp_b4ds = 0x00000030, + .mmdc_grp_b5ds = 0x00000030, + .mmdc_grp_b6ds = 0x00000030, + .mmdc_grp_b7ds = 0x00000030, + + /* DQM[0:7]: Differential input, 40 ohm */ + .mmdc_dram_dqm0 = 0x00020030, + .mmdc_dram_dqm1 = 0x00020030, + .mmdc_dram_dqm2 = 0x00020030, + .mmdc_dram_dqm3 = 0x00020030, + .mmdc_dram_dqm4 = 0x00020030, + .mmdc_dram_dqm5 = 0x00020030, + .mmdc_dram_dqm6 = 0x00020030, + .mmdc_dram_dqm7 = 0x00020030, +}; + +/* MT41K128M16JT-125 */ +static struct mx6_ddr3_cfg mt41k128m16jt_125 = { + .mem_speed = 1600, + .density = 2, + .width = 16, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .pagesz = 2, + .trcd = 1375, + .trcmin = 4875, + .trasmin = 3500, +}; + +/* GW54xx specific calibration */ +static struct mx6_mmdc_calibration gw54xx_mmdc_calibration = { + /* write leveling calibration determine */ + .mmdc_p0_mpwldectrl0 = 0x00210021, + .mmdc_p0_mpwldectrl1 = 0x00284024, + .mmdc_p1_mpwldectrl0 = 0x0018002b, + .mmdc_p1_mpwldectrl1 = 0x000c801f, + /* Read DQS Gating calibration */ + .mmdc_p0_mpdgctrl0 = 0x43430354, + .mmdc_p0_mpdgctrl1 = 0x034e0344, + .mmdc_p1_mpdgctrl0 = 0x43500359, + .mmdc_p1_mpdgctrl1 = 0x034b031c, + /* Read Calibration: DQS delay relative to DQ read access */ + .mmdc_p0_mprddlctl = 0x3e363abe, + .mmdc_p1_mprddlctl = 0x35b23040, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .mmdc_p0_mpwrdlctl = 0x3839403c, + .mmdc_p1_mpwrdlctl = 0x45b6483c, +}; + +/* GW53xx specific calibration */ +static struct mx6_mmdc_calibration gw53xx_mmdc_calibration = { + /* write leveling calibration determine */ + .mmdc_p0_mpwldectrl0 = 0x007c007e, + .mmdc_p0_mpwldectrl1 = 0x003b007c, + .mmdc_p1_mpwldectrl0 = 0x001f002b, + .mmdc_p1_mpwldectrl1 = 0x003f003f, + /* Read DQS Gating calibration */ + .mmdc_p0_mpdgctrl0 = 0x42550254, + .mmdc_p0_mpdgctrl1 = 0x023d023d, + .mmdc_p1_mpdgctrl0 = 0x423c027e, + .mmdc_p1_mpdgctrl1 = 0x021c0238, + /* Read Calibration: DQS delay relative to DQ read access */ + .mmdc_p0_mprddlctl = 0x484a4e4b, + .mmdc_p1_mprddlctl = 0x4b4d4e4b, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .mmdc_p0_mpwrdlctl = 0x37342f32, + .mmdc_p1_mpwrdlctl = 0x3f33372b, +}; + +/* GW52xx specific calibration */ +static struct mx6_mmdc_calibration gw52xx_mmdc_calibration = { + /* write leveling calibration determine */ + .mmdc_p0_mpwldectrl0 = 0x0040003C, + .mmdc_p0_mpwldectrl1 = 0x0032003E, + /* Read DQS Gating calibration */ + .mmdc_p0_mpdgctrl0 = 0x42350231, + .mmdc_p0_mpdgctrl1 = 0x021A0218, + /* Read Calibration: DQS delay relative to DQ read access */ + .mmdc_p0_mprddlctl = 0x4B4B4E49, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .mmdc_p0_mpwrdlctl = 0x3F3F3035, +}; + +/* GW51xx specific calibration */ +static struct mx6_mmdc_calibration gw51xx_mmdc_calibration = { + /* write leveling calibration determine */ + .mmdc_p0_mpwldectrl0 = 0x0040003C, + .mmdc_p0_mpwldectrl1 = 0x0032003E, + /* Read DQS Gating calibration */ + .mmdc_p0_mpdgctrl0 = 0x42350231, + .mmdc_p0_mpdgctrl1 = 0x021A0218, + /* Read Calibration: DQS delay relative to DQ read access */ + .mmdc_p0_mprddlctl = 0x4B4B4E49, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .mmdc_p0_mpwrdlctl = 0x3F3F3035, +}; + +static void spl_dram_init(int ddr_cfg) +{ + struct mx6_spl_data *data = (struct mx6_spl_data *) + ((CONFIG_SPL_TEXT_BASE - sizeof(struct mx6_spl_data)) & ~0xf); + u32 cpurev, imxtype; + int width, size; + struct mx6_ddr3_cfg *mem = &mt41k128m16jt_125; + struct mx6_mmdc_calibration *calib; + struct mx6_ddr_sysinfo sysinfo = { + .dsize = (8 << (ddr_cfg & 0xff))/32, + .cs_density = (16 << (ddr_cfg>>8))/128, + /* single chip select */ + .ncs = 1, + .cs1_mirror = 0, + .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */ +#ifdef RTT_NOM_120OHM + .rtt_nom = 2 /*DDR3_RTT_120_OHM*/, /* RTT_Nom = RZQ/2 */ +#else + .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */ +#endif + .walat = 1, /* Write additional latency */ + .ralat = 5, /* Read additional latency */ + .mif3_mode = 3, /* Command prediction working mode */ + .bi_on = 1, /* Bank interleaving enabled */ + .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ + .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + }; + u8 model[16]; + + i2c_read(GSC_EEPROM_ADDR, 0x30, 1, model, 16); + debug("model:%s\n", model); + + /* + * MMDC Calibration requires the following data: + * mx6_mmdc_calibration - board-specific calibration (routing delays) + * mx6_ddr_sysinfo - board-specific memory architecture (width/cs/etc) + * mx6_ddr_cfg - chip specific timing/layout details + */ + switch (model[3]) { + case '1': + calib = &gw51xx_mmdc_calibration; + break; + case '2': + calib = &gw52xx_mmdc_calibration; + break; + case '3': + calib = &gw53xx_mmdc_calibration; + break; + default: + case '4': + calib = &gw54xx_mmdc_calibration; + break; + } + + cpurev = get_cpu_rev(); + imxtype = (cpurev & 0xFF000) >> 12; + size = (16 << (ddr_cfg >> 8)); + width = (8 << (ddr_cfg & 0xff)); + data->mem_dram_size = size * 1024 * 1024; + + get_imx_type(imxtype); + + switch (imxtype) { + case MXC_CPU_MX6Q: + mx6_dram_iocfg(width, &mx6dq_ctrl, &mmdc_ioregs); + mx6_dram_cfg(&sysinfo, &mx6_ddrcfg, calib, mem); + break; + case MXC_CPU_MX6DL: + default: + mx6_dram_iocfg(width, &mx6sdl_ctrl, &mmdc_ioregs); + mx6_dram_cfg(&sysinfo, &mx6_ddrcfg, calib, mem); + break; + } +} + +/* + * called from C runtime startup code (arch/arm/lib/crt0.S:_main) + * - we have a stack and a place to store GD, both in SRAM + * - no variable global data is available + */ +void board_init_f(ulong dummy) +{ + int ddrcfg; + + /* iomux and setup of i2c */ + i2c_setup_iomux(); + + /* TODO: possible to get console support at this point for debugging? */ + timer_init(); + ddrcfg = read_eeprom(); + spl_dram_init(ddrcfg); + + arch_cpu_init(); + + /* Clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + /* Set global data pointer. */ + gd = &gdata; + + board_early_init_f(); + + preloader_console_init(); + + if (is_cpu_type(MXC_CPU_MX6Q)) + puts("CPU: IMX6Q\n"); + else if (is_cpu_type(MXC_CPU_MX6DL)) + puts("CPU: IMX6DL\n"); + else + puts("CPU: unsupported\n"); + printf("SDRAM: %dMB %dbit\n", (16 << (ddrcfg>>8)), + (8 << (ddrcfg & 0xff))); + + board_init_r(NULL, 0); +} + +/* called from board_init_r() to decide what spl_*_load_image() to call */ +u32 spl_boot_device(void) +{ + puts("Boot Device: "); + switch (get_boot_device()) { + case MX6_MMC_BOOT: + printf("uSD\n"); + return BOOT_DEVICE_MMC1; + case MX6_NAND_BOOT: + printf("NAND\n"); + return BOOT_DEVICE_NAND; + case MX6_SATA_BOOT: + printf("SATA\n"); + return BOOT_DEVICE_SATA; + default: + printf("UNKNOWN\n"); + return BOOT_DEVICE_NONE; + } +} + +#if defined(CONFIG_SPL_MMC_SUPPORT) +/* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */ +u32 spl_boot_mode(void) +{ + switch (get_boot_device()) { + /* for MMC return either RAW or FAT mode */ + case BOOT_DEVICE_MMC1: +#ifdef CONFIG_SPL_FAT_SUPPORT + return MMCSD_MODE_FAT; +#else + return MMCSD_MODE_RAW; +#endif + break; + default: + puts("spl: ERROR: unsupported device\n"); + hang(); + } +} +#endif + +void reset_cpu(ulong addr) +{ +} +#endif + diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.cfg b/board/gateworks/gw_ventana/gw_ventana_spl.cfg new file mode 100644 index 0000000..9ab95f5 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.cfg @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 Gateworks Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Refer doc/README.imximage for more details about how-to configure + * and create imximage boot image + * + * The syntax is taken as close as possible with the kwbimage + */ + +/* image version */ +IMAGE_VERSION 2 + +/* + * Boot Device : one of + * spi, sd, nand, sata + */ +#ifdef CONFIG_SPI_FLASH +BOOT_FROM spi +#else +BOOT_FROM nand +#endif + +#define __ASSEMBLY__ +#include <config.h> +#include "asm/arch/iomux.h" +#include "asm/arch/crm_regs.h" +#include "clocks.cfg" diff --git a/boards.cfg b/boards.cfg index a7be5a3..aa48f89 100644 --- a/boards.cfg +++ b/boards.cfg @@ -320,11 +320,7 @@ Active arm armv7 mx6 freescale mx6qsabreauto Active arm armv7 mx6 freescale mx6sabresd mx6dlsabresd mx6sabresd:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL Fabio Estevam fabio.estevam@freescale.com Active arm armv7 mx6 freescale mx6sabresd mx6qsabresd mx6sabresd:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q Fabio Estevam fabio.estevam@freescale.com Active arm armv7 mx6 freescale mx6slevk mx6slevk mx6slevk:IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL Fabio Estevam fabio.estevam@freescale.com -Active arm armv7 mx6 gateworks gw_ventana gwventanadl gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6DL,DDR_MB=512 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanadl1g gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6DL,DDR_MB=1024 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=512 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq1g gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=1024 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq1gspi gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=1024,SPI_FLASH Tim Harvey tharvey@gateworks.com +Active arm armv7 mx6 gateworks gw_ventana gwventana gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6QDL,SPL Tim Harvey tharvey@gateworks.com Active arm armv7 mx6 solidrun hummingboard hummingboard_solo hummingboard:IMX_CONFIG=board/solidrun/hummingboard/solo.cfg,MX6S,DDR_MB=512 Jon Nettleton jon.nettleton@gmail.com Active arm armv7 omap3 - overo omap3_overo - Steve Sakoman sakoman@gmail.com Active arm armv7 omap3 - pandora omap3_pandora - Grazvydas Ignotas notasas@gmail.com diff --git a/include/config/uboot.release b/include/config/uboot.release new file mode 100644 index 0000000..0e37110 --- /dev/null +++ b/include/config/uboot.release @@ -0,0 +1 @@ +2014.04-rc1-00227-g1879963-dirty diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h index 3398390..f6dc52a 100644 --- a/include/configs/gw_ventana.h +++ b/include/configs/gw_ventana.h @@ -7,6 +7,17 @@ #ifndef __CONFIG_H #define __CONFIG_H
+/* SPL */ +#define CONFIG_SPL_NAND_SUPPORT +/* +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SPL_SATA_SUPPORT +#define CONFIG_SPL_FAT_SUPPORT +*/ +/* Location in NAND to read U-Boot from */ +#define CONFIG_SYS_NAND_U_BOOT_OFFS (14 * 1024 * 1024) + +#include "imx6_spl.h" /* common IMX6 SPL configuration */ #include "mx6_common.h" #define CONFIG_MX6 #define CONFIG_DISPLAY_CPUINFO /* display cpu info */ @@ -242,7 +253,7 @@ "mtdparts=nor:512k(uboot),64k(env),2m(kernel),-(rootfs)" #else #define MTDIDS_DEFAULT "nand0=nand" -#define MTDPARTS_DEFAULT "mtdparts=nand:16m(uboot),1m(env),-(rootfs)" +#define MTDPARTS_DEFAULT "mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs)" #endif
/* Persistent Environment Config */

On Wed, Apr 2, 2014 at 11:01 PM, Tim Harvey tharvey@gateworks.com wrote:
Switch to an SPL image. The SPL for Ventana does the following:
- setup i2c and read the factory programmed EEPROM to obtain DRAM config and model for board-specific calibration data
- configure DRAM per CPU/size/layout/devices/calibration
- load u-boot.img from NAND and jump to it
This allows for a single SPL+u-boot.img to replace the previous multiple board configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com
<snip>
diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.c b/board/gateworks/gw_ventana/gw_ventana_spl.c new file mode 100644 index 0000000..492c814 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -0,0 +1,394 @@ +/*
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/mx6_ddr_regs.h>
this header is non-existent and the include should be removed. I left this in by accident.
Tim

Hi Tim,
On 03/04/2014 08:01, Tim Harvey wrote:
Switch to an SPL image. The SPL for Ventana does the following:
- setup i2c and read the factory programmed EEPROM to obtain DRAM config and model for board-specific calibration data
- configure DRAM per CPU/size/layout/devices/calibration
- load u-boot.img from NAND and jump to it
This allows for a single SPL+u-boot.img to replace the previous multiple board configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com
board/gateworks/gw_ventana/Makefile | 2 +- board/gateworks/gw_ventana/README | 91 +++--- board/gateworks/gw_ventana/gw_ventana.c | 5 +- board/gateworks/gw_ventana/gw_ventana.cfg | 15 - board/gateworks/gw_ventana/gw_ventana_spl.c | 394 ++++++++++++++++++++++++++ board/gateworks/gw_ventana/gw_ventana_spl.cfg | 29 ++ boards.cfg | 6 +- include/config/uboot.release | 1 + include/configs/gw_ventana.h | 13 +- 9 files changed, 500 insertions(+), 56 deletions(-) create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.c create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.cfg create mode 100644 include/config/uboot.release
diff --git a/board/gateworks/gw_ventana/Makefile b/board/gateworks/gw_ventana/Makefile index e8dab89..8b239ae 100644 --- a/board/gateworks/gw_ventana/Makefile +++ b/board/gateworks/gw_ventana/Makefile @@ -6,5 +6,5 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y := gw_ventana.o gsc.o +obj-y := gw_ventana.o gsc.o gw_ventana_spl.o
I think that gw_ventana_spl.o is always built. Should we use instead :
obj-$(CONFIG_SPL_BUILD) += gw_ventana_spl.o
diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README index 9e697d6..c45d4b8 100644 --- a/board/gateworks/gw_ventana/README +++ b/board/gateworks/gw_ventana/README @@ -3,53 +3,80 @@ U-Boot for the Gateworks Ventana Product Family boards This file contains information for the port of U-Boot to the Gateworks Ventana Product family boards.
-1. Boot source, boot from NAND +1. Secondary Program Loader (SPL) +---------------------------------
+The i.MX6 has a BOOT ROM PPL (Primary Program Loader) which supports loading +an executable image from various boot devices.
+The Gateworks Ventana board config uses an SPL build configuration. This +will build the following artifacts from u-boot source:
- SPL - Secondary Program Loader that the i.MX6 BOOT ROM (Primary Program
Loader) boots. This detects CPU/DRAM configuration, configures
The DRAM controller, loads u-boot.img from the detected boot device,
and jumps to it. As this is booted from the PPL, it has an IVT/DCD
table.
- u-boot.img - The main u-boot core which is u-boot.bin with a image header.
+2. Build +--------
+To build U-Boot for the Gateworks Ventana product family:
- make gwventana_config
- make
+3. Boot source, boot from NAND
The i.MX6 BOOT ROM expects some structures that provide details of NAND layout and bad block information (referred to as 'bootstreams') which are replicated -multiple times in NAND. The number of replications is configurable through -board strapping options and eFUSE settings. The Freescale 'kobs-ng' -application from the Freescale LTIB BSP, which runs under Linux, must be used -to program the bootstream in order to setup the replicated headers correctly. +multiple times in NAND. The number of replications and their spacing (referred +to as search stride) is configurable through board strapping options and/or +eFUSE settings (BOOT_SEARCH_COUNT / Pages in block from BOOT_CFG2). In +addition, the i.MX6 BOOT ROM Flash Configuration Block (FCB) supports two +copies of a bootloader in flash in the case that a bad block has corrupted one. The Freescale 'kobs-ng' application from the Freescale LTIB BSP, which runs
Line too long ?
+under Linux and operates on an MTD partition, must be used to program the +bootstream in order to setup this flash structure correctly.
The Gateworks Ventana boards with NAND flash have been factory programmed such that their eFUSE settings expect 2 copies of the boostream (this is specified by providing kobs-ng with the --search_exponent=1 argument). Once in -Linux with MTD support for the NAND on /dev/mtd0 you can program the boostream +Linux with MTD support for the NAND on /dev/mtd0 you can program the SPL with:
-kobs-ng init -v -x --search_exponent=1 u-boot.imx +kobs-ng init -v -x --search_exponent=1 SPL
-The kobs-ng application uses an imximage (u-boot.imx) which contains the -Image Vector Table (IVT) and Device Configuration Data (DCD) structures that -the i.MX6 BOOT ROM requires to boot. The kobs-ng adds the Firmware -Configuration Block (FCB) and Discovered Bad Block Table (DBBT). +The kobs-ng application uses an imximage which contains the Image Vector Table +(IVT) and Device Configuration Data (DCD) structures that the i.MX6 BOOT ROM +requires to boot. The kobs-ng adds the Firmware Configuration Block (FCB) and +Discovered Bad Block Table (DBBT). The SPL build artifact from u-boot is +an imximage.
-This information is taken from:
+The u-boot.img, which is the non SPL u-boot binary appended to a u-boot image +header must be programmed in the NAND flash boot device at an offset hard +coded in the SPL. For the Ventana boards, this has been chosen to be 14MB. +The image can be programmed from either u-boot or Linux:
-More details about the i.MX6 BOOT ROM can be found in the IMX6 reference manual.
-2. Build
+u-boot: +Ventana > setenv mtdparts mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs) +Ventana > tftp ${loadaddr} u-boot.img && nand erase.part uboot && \
nand write ${loadaddr} uboot ${filesize}
-There are several Gateworks Ventana boards that share a simliar design but -vary based on CPU, Memory configuration, and subloaded devices. Although -the subloaded devices are handled dynamically in the bootloader using -factory configured EEPROM data to modify the device-tree, the CPU choice -(IMX6Q vs IMX6DL) and memory configurations are currently compile-time -options. +Linux: +nandwrite /dev/mtd1 u-boot.img
-The following Gateworks Ventana configurations exist:
- gwventanaq1gspi: MX6Q,1GB,SPI FLASH
- gwventanaq : MX6Q,512MB,NAND FLASH
- gwventanaq1g : MX6Q,1GB,NAND FLASH
- gwventanadl : MX6DL,512MB,NAND FLASH
- gwventanadl1g : MX6DL,1GB,NAND FLASH
+The above assumes the default Ventana partitioning scheme which is configured +via the mtdparts env var:
- spl: 14MB
- uboot: 2M
- env: 1M
- rootfs: the rest
-To build U-Boot for the MX6Q,1GB,NAND FLASH for example: +This information is taken from:
- make gwventanaq1g_config
- make
+More details about the i.MX6 BOOT ROM can be found in the IMX6 reference manual.
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index ebf7e7d..7508141 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -1019,8 +1019,9 @@ int board_early_init_f(void)
int dram_init(void) {
- gd->ram_size = get_ram_size((void *)PHYS_SDRAM,
CONFIG_DDR_MB*1024*1024);
- struct mx6_spl_data *data = (struct mx6_spl_data *)
((CONFIG_SPL_TEXT_BASE - sizeof(struct mx6_spl_data)) & ~0xf);
Ok, you have *data on the stack, you initialize to a magic number and then you do nothing with it.
- gd->ram_size = data->mem_dram_size;
We have already talked about it. A runtime detection is absolutely preferable, as suggested by Igor.
return 0; } diff --git a/board/gateworks/gw_ventana/gw_ventana.cfg b/board/gateworks/gw_ventana/gw_ventana.cfg index 27f0974..9ab95f5 100644 --- a/board/gateworks/gw_ventana/gw_ventana.cfg +++ b/board/gateworks/gw_ventana/gw_ventana.cfg @@ -24,21 +24,6 @@ BOOT_FROM nand
#define __ASSEMBLY__ #include <config.h> -#include "asm/arch/mx6-ddr.h" #include "asm/arch/iomux.h" #include "asm/arch/crm_regs.h"
-/* Memory configuration (size is overridden via eeprom config) */ -#include "../../boundary/nitrogen6x/ddr-setup.cfg" -#if defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 1024
- #include "../../boundary/nitrogen6x/1066mhz_4x128mx16.cfg"
-#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 1024
- #include "../../boundary/nitrogen6x/800mhz_4x128mx16.cfg"
-#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 512
- #include "../../boundary/nitrogen6x/800mhz_2x128mx16.cfg"
-#elif defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 512
- #include "../../boundary/nitrogen6x/800mhz_2x128mx16.cfg"
-#else
- #error "Unsupported CPU/Memory configuration"
-#endif #include "clocks.cfg"
Right - this is what I have expected for the .cfg file adding SPL.
diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.c b/board/gateworks/gw_ventana/gw_ventana_spl.c new file mode 100644 index 0000000..492c814 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -0,0 +1,394 @@ +/*
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/mx6_ddr_regs.h> +#include <asm/arch/mx6-ddr.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/sys_proto.h> +#include <asm/imx-common/boot_mode.h> +#include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> +#ifdef CONFIG_SPL +#include <spl.h> +#endif
+DECLARE_GLOBAL_DATA_PTR;
+#if defined(CONFIG_SPL_BUILD)
I will drop it from here and conditionally compile this file if SPL_BUILD is set.
+#define RTT_NOM_120OHM /* use 120ohm Rtt_nom vs 60ohm (lower power) */ +#define I2C_GSC 0 +#define GSC_EEPROM_ADDR 0x51 +#define GSC_EEPROM_DDR_SIZE 0x2B /* enum (512,1024,2048) MB */ +#define GSC_EEPROM_DDR_WIDTH 0x2D /* enum (32,64) bit */ +#define I2C_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
- PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
- PAD_CTL_ODE | PAD_CTL_SRE_FAST)
+#define PC MUX_PAD_CTRL(I2C_PAD_CTRL) +#define CONFIG_SYS_I2C_SPEED 100000
+/* I2C1: GSC */ +static struct i2c_pads_info mx6q_i2c_pad_info0 = {
- .scl = {
.i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC,
.gp = IMX_GPIO_NR(3, 21)
- },
- .sda = {
.i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC,
.gp = IMX_GPIO_NR(3, 28)
- }
+}; +static struct i2c_pads_info mx6dl_i2c_pad_info0 = {
- .scl = {
.i2c_mode = MX6DL_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC,
.gp = IMX_GPIO_NR(3, 21)
- },
- .sda = {
.i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC,
.gp = IMX_GPIO_NR(3, 28)
- }
+};
+static void i2c_setup_iomux(void) +{
- if (is_cpu_type(MXC_CPU_MX6Q))
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0);
- else
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0);
+}
+static u16 +read_eeprom(void)
+{
- u8 data[3];
- /*
* On a board with a missing/depleted backup battery for GSC, the
* board may be ready to probe the GSC before its firmware is
* running. We will wait here indefinately for the GSC/EEPROM.
*/
- while (1) {
if (0 == i2c_set_bus_num(I2C_GSC) &&
0 == i2c_probe(GSC_EEPROM_ADDR))
break;
/* TODO: mdelay hangs at this point
mdelay(1);
*/
- }
- i2c_read(GSC_EEPROM_ADDR, GSC_EEPROM_DDR_SIZE, 1, data, 3);
- return (data[0] << 8) | data[2];
+}
This is a simplified version of the same function in gw_ventana.c. By submitting the original patch, you convinced me that due to hardware issues the read can fails the first time and you add gsc_i2c_read(). Why do we have no problem with i2c in SPL ? It should be even worse.
+/* configure mx6 mmdc io registers */ +struct mx6_mmdc_ioregs mmdc_ioregs = {
- /* DDR3 */
- .mmdc_grp_ddr_type = 0x000c0000,
- /* disable DDR pullups */
- .mmdc_grp_ddrpke = 0x00000000,
- /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */
- .mmdc_dram_sdclk_0 = 0x00020030,
- .mmdc_dram_sdclk_1 = 0x00020030,
- .mmdc_dram_cas = 0x00020030,
- .mmdc_dram_ras = 0x00020030,
- .mmdc_dram_reset = 0x00020030,
- /* ADDR[00:16], SDBA[0:1]: 40 ohm */
- .mmdc_grp_addds = 0x00000030,
- /* SDCKE[0:1]: 100k pull-up */
- .mmdc_dram_sdcke0 = 0x00003000,
- .mmdc_dram_sdcke1 = 0x00003000,
- /* SDBA2: pull-up disabled */
- .mmdc_dram_sdba2 = 0x00000000,
- /* SDODT[0:1]: 100k pull-up, 40 ohm */
- .mmdc_dram_sdodt0 = 0x00003030,
- .mmdc_dram_sdodt1 = 0x00003030,
- /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */
- .mmdc_grp_ctlds = 0x00000030,
- /* SDQS[0:7]: Differential input, 40 ohm */
- .mmdc_ddrmode_ctl = 0x00020000,
- .mmdc_dram_sdqs0 = 0x00000030,
- .mmdc_dram_sdqs1 = 0x00000030,
- .mmdc_dram_sdqs2 = 0x00000030,
- .mmdc_dram_sdqs3 = 0x00000030,
- .mmdc_dram_sdqs4 = 0x00000030,
- .mmdc_dram_sdqs5 = 0x00000030,
- .mmdc_dram_sdqs6 = 0x00000030,
- .mmdc_dram_sdqs7 = 0x00000030,
- /* DATA[00:63]: Differential input, 40 ohm */
- .mmdc_grp_ddrmode = 0x00020000,
- .mmdc_grp_b0ds = 0x00000030,
- .mmdc_grp_b1ds = 0x00000030,
- .mmdc_grp_b2ds = 0x00000030,
- .mmdc_grp_b3ds = 0x00000030,
- .mmdc_grp_b4ds = 0x00000030,
- .mmdc_grp_b5ds = 0x00000030,
- .mmdc_grp_b6ds = 0x00000030,
- .mmdc_grp_b7ds = 0x00000030,
- /* DQM[0:7]: Differential input, 40 ohm */
- .mmdc_dram_dqm0 = 0x00020030,
- .mmdc_dram_dqm1 = 0x00020030,
- .mmdc_dram_dqm2 = 0x00020030,
- .mmdc_dram_dqm3 = 0x00020030,
- .mmdc_dram_dqm4 = 0x00020030,
- .mmdc_dram_dqm5 = 0x00020030,
- .mmdc_dram_dqm6 = 0x00020030,
- .mmdc_dram_dqm7 = 0x00020030,
+};
I will suggest you move these structure in a separate file. It is then easier for a board developer to understand what is very board specific.
+/* MT41K128M16JT-125 */ +static struct mx6_ddr3_cfg mt41k128m16jt_125 = {
- .mem_speed = 1600,
- .density = 2,
- .width = 16,
- .banks = 8,
- .rowaddr = 14,
- .coladdr = 10,
- .pagesz = 2,
- .trcd = 1375,
- .trcmin = 4875,
- .trasmin = 3500,
+};
+/* GW54xx specific calibration */ +static struct mx6_mmdc_calibration gw54xx_mmdc_calibration = {
- /* write leveling calibration determine */
- .mmdc_p0_mpwldectrl0 = 0x00210021,
- .mmdc_p0_mpwldectrl1 = 0x00284024,
- .mmdc_p1_mpwldectrl0 = 0x0018002b,
- .mmdc_p1_mpwldectrl1 = 0x000c801f,
- /* Read DQS Gating calibration */
- .mmdc_p0_mpdgctrl0 = 0x43430354,
- .mmdc_p0_mpdgctrl1 = 0x034e0344,
- .mmdc_p1_mpdgctrl0 = 0x43500359,
- .mmdc_p1_mpdgctrl1 = 0x034b031c,
- /* Read Calibration: DQS delay relative to DQ read access */
- .mmdc_p0_mprddlctl = 0x3e363abe,
- .mmdc_p1_mprddlctl = 0x35b23040,
- /* Write Calibration: DQ/DM delay relative to DQS write access */
- .mmdc_p0_mpwrdlctl = 0x3839403c,
- .mmdc_p1_mpwrdlctl = 0x45b6483c,
+};
+/* GW53xx specific calibration */ +static struct mx6_mmdc_calibration gw53xx_mmdc_calibration = {
- /* write leveling calibration determine */
- .mmdc_p0_mpwldectrl0 = 0x007c007e,
- .mmdc_p0_mpwldectrl1 = 0x003b007c,
- .mmdc_p1_mpwldectrl0 = 0x001f002b,
- .mmdc_p1_mpwldectrl1 = 0x003f003f,
- /* Read DQS Gating calibration */
- .mmdc_p0_mpdgctrl0 = 0x42550254,
- .mmdc_p0_mpdgctrl1 = 0x023d023d,
- .mmdc_p1_mpdgctrl0 = 0x423c027e,
- .mmdc_p1_mpdgctrl1 = 0x021c0238,
- /* Read Calibration: DQS delay relative to DQ read access */
- .mmdc_p0_mprddlctl = 0x484a4e4b,
- .mmdc_p1_mprddlctl = 0x4b4d4e4b,
- /* Write Calibration: DQ/DM delay relative to DQS write access */
- .mmdc_p0_mpwrdlctl = 0x37342f32,
- .mmdc_p1_mpwrdlctl = 0x3f33372b,
+};
+/* GW52xx specific calibration */ +static struct mx6_mmdc_calibration gw52xx_mmdc_calibration = {
- /* write leveling calibration determine */
- .mmdc_p0_mpwldectrl0 = 0x0040003C,
- .mmdc_p0_mpwldectrl1 = 0x0032003E,
- /* Read DQS Gating calibration */
- .mmdc_p0_mpdgctrl0 = 0x42350231,
- .mmdc_p0_mpdgctrl1 = 0x021A0218,
- /* Read Calibration: DQS delay relative to DQ read access */
- .mmdc_p0_mprddlctl = 0x4B4B4E49,
- /* Write Calibration: DQ/DM delay relative to DQS write access */
- .mmdc_p0_mpwrdlctl = 0x3F3F3035,
+};
+/* GW51xx specific calibration */ +static struct mx6_mmdc_calibration gw51xx_mmdc_calibration = {
- /* write leveling calibration determine */
- .mmdc_p0_mpwldectrl0 = 0x0040003C,
- .mmdc_p0_mpwldectrl1 = 0x0032003E,
- /* Read DQS Gating calibration */
- .mmdc_p0_mpdgctrl0 = 0x42350231,
- .mmdc_p0_mpdgctrl1 = 0x021A0218,
- /* Read Calibration: DQS delay relative to DQ read access */
- .mmdc_p0_mprddlctl = 0x4B4B4E49,
- /* Write Calibration: DQ/DM delay relative to DQS write access */
- .mmdc_p0_mpwrdlctl = 0x3F3F3035,
+};
+static void spl_dram_init(int ddr_cfg) +{
- struct mx6_spl_data *data = (struct mx6_spl_data *)
((CONFIG_SPL_TEXT_BASE - sizeof(struct mx6_spl_data)) & ~0xf);
- u32 cpurev, imxtype;
- int width, size;
- struct mx6_ddr3_cfg *mem = &mt41k128m16jt_125;
- struct mx6_mmdc_calibration *calib;
- struct mx6_ddr_sysinfo sysinfo = {
.dsize = (8 << (ddr_cfg & 0xff))/32,
.cs_density = (16 << (ddr_cfg>>8))/128,
/* single chip select */
.ncs = 1,
.cs1_mirror = 0,
.rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */
+#ifdef RTT_NOM_120OHM
.rtt_nom = 2 /*DDR3_RTT_120_OHM*/, /* RTT_Nom = RZQ/2 */
+#else
.rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */
+#endif
.walat = 1, /* Write additional latency */
.ralat = 5, /* Read additional latency */
.mif3_mode = 3, /* Command prediction working mode */
.bi_on = 1, /* Bank interleaving enabled */
.sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */
.rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */
- };
- u8 model[16];
- i2c_read(GSC_EEPROM_ADDR, 0x30, 1, model, 16);
- debug("model:%s\n", model);
- /*
* MMDC Calibration requires the following data:
* mx6_mmdc_calibration - board-specific calibration (routing delays)
* mx6_ddr_sysinfo - board-specific memory architecture (width/cs/etc)
* mx6_ddr_cfg - chip specific timing/layout details
*/
- switch (model[3]) {
- case '1':
calib = &gw51xx_mmdc_calibration;
break;
- case '2':
calib = &gw52xx_mmdc_calibration;
break;
- case '3':
calib = &gw53xx_mmdc_calibration;
break;
- default:
- case '4':
calib = &gw54xx_mmdc_calibration;
break;
- }
- cpurev = get_cpu_rev();
- imxtype = (cpurev & 0xFF000) >> 12;
- size = (16 << (ddr_cfg >> 8));
- width = (8 << (ddr_cfg & 0xff));
- data->mem_dram_size = size * 1024 * 1024;
- get_imx_type(imxtype);
- switch (imxtype) {
- case MXC_CPU_MX6Q:
mx6_dram_iocfg(width, &mx6dq_ctrl, &mmdc_ioregs);
mx6_dram_cfg(&sysinfo, &mx6_ddrcfg, calib, mem);
break;
- case MXC_CPU_MX6DL:
- default:
mx6_dram_iocfg(width, &mx6sdl_ctrl, &mmdc_ioregs);
mx6_dram_cfg(&sysinfo, &mx6_ddrcfg, calib, mem);
break;
- }
+}
+/*
- called from C runtime startup code (arch/arm/lib/crt0.S:_main)
- we have a stack and a place to store GD, both in SRAM
- no variable global data is available
- */
+void board_init_f(ulong dummy) +{
- int ddrcfg;
- /* iomux and setup of i2c */
- i2c_setup_iomux();
- /* TODO: possible to get console support at this point for debugging? */
- timer_init();
- ddrcfg = read_eeprom();
- spl_dram_init(ddrcfg);
- arch_cpu_init();
- /* Clear the BSS. */
- memset(__bss_start, 0, __bss_end - __bss_start);
- /* Set global data pointer. */
- gd = &gdata;
- board_early_init_f();
- preloader_console_init();
- if (is_cpu_type(MXC_CPU_MX6Q))
puts("CPU: IMX6Q\n");
- else if (is_cpu_type(MXC_CPU_MX6DL))
puts("CPU: IMX6DL\n");
- else
puts("CPU: unsupported\n");
- printf("SDRAM: %dMB %dbit\n", (16 << (ddrcfg>>8)),
(8 << (ddrcfg & 0xff)));
Really do we need this in SPL ? Is not enough in U-Boot ?
- board_init_r(NULL, 0);
+}
Mmhhh...apart the access to the eeprom to get the ram size, this function should be common.
+/* called from board_init_r() to decide what spl_*_load_image() to call */ +u32 spl_boot_device(void) +{
- puts("Boot Device: ");
- switch (get_boot_device()) {
- case MX6_MMC_BOOT:
printf("uSD\n");
return BOOT_DEVICE_MMC1;
- case MX6_NAND_BOOT:
printf("NAND\n");
return BOOT_DEVICE_NAND;
- case MX6_SATA_BOOT:
printf("SATA\n");
return BOOT_DEVICE_SATA;
- default:
printf("UNKNOWN\n");
return BOOT_DEVICE_NONE;
- }
+}
This function (without unneeded printf) should be made common. Feel free to add a spl.c file inside ./arch/arm/imx-common
+#if defined(CONFIG_SPL_MMC_SUPPORT) +/* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */ +u32 spl_boot_mode(void) +{
- switch (get_boot_device()) {
- /* for MMC return either RAW or FAT mode */
- case BOOT_DEVICE_MMC1:
+#ifdef CONFIG_SPL_FAT_SUPPORT
return MMCSD_MODE_FAT;
+#else
return MMCSD_MODE_RAW;
+#endif
break;
- default:
puts("spl: ERROR: unsupported device\n");
hang();
- }
+} +#endif
+void reset_cpu(ulong addr) +{ +} +#endif
Ditto
diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.cfg b/board/gateworks/gw_ventana/gw_ventana_spl.cfg new file mode 100644 index 0000000..9ab95f5 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.cfg @@ -0,0 +1,29 @@ +/*
- Copyright (C) 2013 Gateworks Corporation
- SPDX-License-Identifier: GPL-2.0+
- Refer doc/README.imximage for more details about how-to configure
- and create imximage boot image
- The syntax is taken as close as possible with the kwbimage
- */
+/* image version */ +IMAGE_VERSION 2
+/*
- Boot Device : one of
- spi, sd, nand, sata
- */
+#ifdef CONFIG_SPI_FLASH +BOOT_FROM spi +#else +BOOT_FROM nand +#endif
+#define __ASSEMBLY__ +#include <config.h> +#include "asm/arch/iomux.h" +#include "asm/arch/crm_regs.h" +#include "clocks.cfg"
Mmhhh...which is the reason to have gw_ventana.cfg and gw_ventana_spl.cfg ?
You need the .cfg file to generate the IVT header only for SPL. It is not required for U-Boot, because the boot ROM has already processed the first i.MX header.
diff --git a/boards.cfg b/boards.cfg index a7be5a3..aa48f89 100644 --- a/boards.cfg +++ b/boards.cfg @@ -320,11 +320,7 @@ Active arm armv7 mx6 freescale mx6qsabreauto Active arm armv7 mx6 freescale mx6sabresd mx6dlsabresd mx6sabresd:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL Fabio Estevam fabio.estevam@freescale.com Active arm armv7 mx6 freescale mx6sabresd mx6qsabresd mx6sabresd:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q Fabio Estevam fabio.estevam@freescale.com Active arm armv7 mx6 freescale mx6slevk mx6slevk mx6slevk:IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL Fabio Estevam fabio.estevam@freescale.com -Active arm armv7 mx6 gateworks gw_ventana gwventanadl gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6DL,DDR_MB=512 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanadl1g gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6DL,DDR_MB=1024 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=512 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq1g gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=1024 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq1gspi gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=1024,SPI_FLASH Tim Harvey tharvey@gateworks.com +Active arm armv7 mx6 gateworks gw_ventana gwventana gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6QDL,SPL Tim Harvey tharvey@gateworks.com
Nice, only one entry for all of your boards.
Active arm armv7 mx6 solidrun hummingboard hummingboard_solo hummingboard:IMX_CONFIG=board/solidrun/hummingboard/solo.cfg,MX6S,DDR_MB=512 Jon Nettleton jon.nettleton@gmail.com Active arm armv7 omap3 - overo omap3_overo - Steve Sakoman sakoman@gmail.com Active arm armv7 omap3 - pandora omap3_pandora - Grazvydas Ignotas notasas@gmail.com diff --git a/include/config/uboot.release b/include/config/uboot.release new file mode 100644 index 0000000..0e37110 --- /dev/null +++ b/include/config/uboot.release @@ -0,0 +1 @@ +2014.04-rc1-00227-g1879963-dirty diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h index 3398390..f6dc52a 100644 --- a/include/configs/gw_ventana.h +++ b/include/configs/gw_ventana.h @@ -7,6 +7,17 @@ #ifndef __CONFIG_H #define __CONFIG_H
+/* SPL */ +#define CONFIG_SPL_NAND_SUPPORT +/* +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SPL_SATA_SUPPORT +#define CONFIG_SPL_FAT_SUPPORT +*/ +/* Location in NAND to read U-Boot from */ +#define CONFIG_SYS_NAND_U_BOOT_OFFS (14 * 1024 * 1024)
This is ok - it is your decision where to put it.
May I ask why do you need 14 MB at the beginning ? It seems you lose a lot of place. NAND is cheap nowadays, but...
+#include "imx6_spl.h" /* common IMX6 SPL configuration */ #include "mx6_common.h" #define CONFIG_MX6 #define CONFIG_DISPLAY_CPUINFO /* display cpu info */ @@ -242,7 +253,7 @@ "mtdparts=nor:512k(uboot),64k(env),2m(kernel),-(rootfs)" #else #define MTDIDS_DEFAULT "nand0=nand" -#define MTDPARTS_DEFAULT "mtdparts=nand:16m(uboot),1m(env),-(rootfs)" +#define MTDPARTS_DEFAULT "mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs)"
Best regards, Stefano Babic

On Wed, Apr 23, 2014 at 11:03 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
Hi Stefano,
On 03/04/2014 08:01, Tim Harvey wrote:
Switch to an SPL image. The SPL for Ventana does the following:
- setup i2c and read the factory programmed EEPROM to obtain DRAM config and model for board-specific calibration data
- configure DRAM per CPU/size/layout/devices/calibration
- load u-boot.img from NAND and jump to it
This allows for a single SPL+u-boot.img to replace the previous multiple board configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com
board/gateworks/gw_ventana/Makefile | 2 +- board/gateworks/gw_ventana/README | 91 +++--- board/gateworks/gw_ventana/gw_ventana.c | 5 +- board/gateworks/gw_ventana/gw_ventana.cfg | 15 - board/gateworks/gw_ventana/gw_ventana_spl.c | 394 ++++++++++++++++++++++++++ board/gateworks/gw_ventana/gw_ventana_spl.cfg | 29 ++ boards.cfg | 6 +- include/config/uboot.release | 1 + include/configs/gw_ventana.h | 13 +- 9 files changed, 500 insertions(+), 56 deletions(-) create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.c create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.cfg create mode 100644 include/config/uboot.release
diff --git a/board/gateworks/gw_ventana/Makefile b/board/gateworks/gw_ventana/Makefile index e8dab89..8b239ae 100644 --- a/board/gateworks/gw_ventana/Makefile +++ b/board/gateworks/gw_ventana/Makefile @@ -6,5 +6,5 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y := gw_ventana.o gsc.o +obj-y := gw_ventana.o gsc.o gw_ventana_spl.o
I think that gw_ventana_spl.o is always built. Should we use instead :
obj-$(CONFIG_SPL_BUILD) += gw_ventana_spl.o
yes, you are right. I will change this
diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README index 9e697d6..c45d4b8 100644 --- a/board/gateworks/gw_ventana/README +++ b/board/gateworks/gw_ventana/README @@ -3,53 +3,80 @@ U-Boot for the Gateworks Ventana Product Family boards This file contains information for the port of U-Boot to the Gateworks Ventana Product family boards.
-1. Boot source, boot from NAND +1. Secondary Program Loader (SPL) +---------------------------------
+The i.MX6 has a BOOT ROM PPL (Primary Program Loader) which supports loading +an executable image from various boot devices.
+The Gateworks Ventana board config uses an SPL build configuration. This +will build the following artifacts from u-boot source:
- SPL - Secondary Program Loader that the i.MX6 BOOT ROM (Primary Program
Loader) boots. This detects CPU/DRAM configuration, configures
The DRAM controller, loads u-boot.img from the detected boot device,
and jumps to it. As this is booted from the PPL, it has an IVT/DCD
table.
- u-boot.img - The main u-boot core which is u-boot.bin with a image header.
+2. Build +--------
+To build U-Boot for the Gateworks Ventana product family:
- make gwventana_config
- make
+3. Boot source, boot from NAND
The i.MX6 BOOT ROM expects some structures that provide details of NAND layout and bad block information (referred to as 'bootstreams') which are replicated -multiple times in NAND. The number of replications is configurable through -board strapping options and eFUSE settings. The Freescale 'kobs-ng' -application from the Freescale LTIB BSP, which runs under Linux, must be used -to program the bootstream in order to setup the replicated headers correctly. +multiple times in NAND. The number of replications and their spacing (referred +to as search stride) is configurable through board strapping options and/or +eFUSE settings (BOOT_SEARCH_COUNT / Pages in block from BOOT_CFG2). In +addition, the i.MX6 BOOT ROM Flash Configuration Block (FCB) supports two +copies of a bootloader in flash in the case that a bad block has corrupted one. The Freescale 'kobs-ng' application from the Freescale LTIB BSP, which runs
Line too long ?
will fix
<snip>
--- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -1019,8 +1019,9 @@ int board_early_init_f(void)
int dram_init(void) {
gd->ram_size = get_ram_size((void *)PHYS_SDRAM,
CONFIG_DDR_MB*1024*1024);
struct mx6_spl_data *data = (struct mx6_spl_data *)
((CONFIG_SPL_TEXT_BASE - sizeof(struct mx6_spl_data)) & ~0xf);
Ok, you have *data on the stack, you initialize to a magic number and then you do nothing with it.
gd->ram_size = data->mem_dram_size;
We have already talked about it. A runtime detection is absolutely preferable, as suggested by Igor.
Yes, as discussed in the other thread I will be changing this to runtime detection and dropping the shared struct between SPL and u-boot.img.
return 0;
}
<snip>
diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.c b/board/gateworks/gw_ventana/gw_ventana_spl.c new file mode 100644 index 0000000..492c814 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -0,0 +1,394 @@ +/*
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <i2c.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/mx6_ddr_regs.h> +#include <asm/arch/mx6-ddr.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/sys_proto.h> +#include <asm/imx-common/boot_mode.h> +#include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> +#ifdef CONFIG_SPL +#include <spl.h> +#endif
+DECLARE_GLOBAL_DATA_PTR;
+#if defined(CONFIG_SPL_BUILD)
I will drop it from here and conditionally compile this file if SPL_BUILD is set.
Agreed - will do this
<snip>
+static u16 +read_eeprom(void) +{
u8 data[3];
/*
* On a board with a missing/depleted backup battery for GSC, the
* board may be ready to probe the GSC before its firmware is
* running. We will wait here indefinately for the GSC/EEPROM.
*/
while (1) {
if (0 == i2c_set_bus_num(I2C_GSC) &&
0 == i2c_probe(GSC_EEPROM_ADDR))
break;
/* TODO: mdelay hangs at this point
mdelay(1);
*/
}
i2c_read(GSC_EEPROM_ADDR, GSC_EEPROM_DDR_SIZE, 1, data, 3);
return (data[0] << 8) | data[2];
+}
This is a simplified version of the same function in gw_ventana.c. By submitting the original patch, you convinced me that due to hardware issues the read can fails the first time and you add gsc_i2c_read(). Why do we have no problem with i2c in SPL ? It should be even worse.
You are absolutely right - I will split out the read_eeprom from gw_ventana.c and re-use it here as well.
+/* configure mx6 mmdc io registers */ +struct mx6_mmdc_ioregs mmdc_ioregs = {
/* DDR3 */
.mmdc_grp_ddr_type = 0x000c0000,
/* disable DDR pullups */
.mmdc_grp_ddrpke = 0x00000000,
/* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */
.mmdc_dram_sdclk_0 = 0x00020030,
.mmdc_dram_sdclk_1 = 0x00020030,
.mmdc_dram_cas = 0x00020030,
.mmdc_dram_ras = 0x00020030,
.mmdc_dram_reset = 0x00020030,
/* ADDR[00:16], SDBA[0:1]: 40 ohm */
.mmdc_grp_addds = 0x00000030,
/* SDCKE[0:1]: 100k pull-up */
.mmdc_dram_sdcke0 = 0x00003000,
.mmdc_dram_sdcke1 = 0x00003000,
/* SDBA2: pull-up disabled */
.mmdc_dram_sdba2 = 0x00000000,
/* SDODT[0:1]: 100k pull-up, 40 ohm */
.mmdc_dram_sdodt0 = 0x00003030,
.mmdc_dram_sdodt1 = 0x00003030,
/* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */
.mmdc_grp_ctlds = 0x00000030,
/* SDQS[0:7]: Differential input, 40 ohm */
.mmdc_ddrmode_ctl = 0x00020000,
.mmdc_dram_sdqs0 = 0x00000030,
.mmdc_dram_sdqs1 = 0x00000030,
.mmdc_dram_sdqs2 = 0x00000030,
.mmdc_dram_sdqs3 = 0x00000030,
.mmdc_dram_sdqs4 = 0x00000030,
.mmdc_dram_sdqs5 = 0x00000030,
.mmdc_dram_sdqs6 = 0x00000030,
.mmdc_dram_sdqs7 = 0x00000030,
/* DATA[00:63]: Differential input, 40 ohm */
.mmdc_grp_ddrmode = 0x00020000,
.mmdc_grp_b0ds = 0x00000030,
.mmdc_grp_b1ds = 0x00000030,
.mmdc_grp_b2ds = 0x00000030,
.mmdc_grp_b3ds = 0x00000030,
.mmdc_grp_b4ds = 0x00000030,
.mmdc_grp_b5ds = 0x00000030,
.mmdc_grp_b6ds = 0x00000030,
.mmdc_grp_b7ds = 0x00000030,
/* DQM[0:7]: Differential input, 40 ohm */
.mmdc_dram_dqm0 = 0x00020030,
.mmdc_dram_dqm1 = 0x00020030,
.mmdc_dram_dqm2 = 0x00020030,
.mmdc_dram_dqm3 = 0x00020030,
.mmdc_dram_dqm4 = 0x00020030,
.mmdc_dram_dqm5 = 0x00020030,
.mmdc_dram_dqm6 = 0x00020030,
.mmdc_dram_dqm7 = 0x00020030,
+};
I will suggest you move these structure in a separate file. It is then easier for a board developer to understand what is very board specific.
hmmm... they are all very board specific but ok.
<snip>
+/*
- called from C runtime startup code (arch/arm/lib/crt0.S:_main)
- we have a stack and a place to store GD, both in SRAM
- no variable global data is available
- */
+void board_init_f(ulong dummy) +{
int ddrcfg;
/* iomux and setup of i2c */
i2c_setup_iomux();
/* TODO: possible to get console support at this point for debugging? */
timer_init();
ddrcfg = read_eeprom();
spl_dram_init(ddrcfg);
arch_cpu_init();
/* Clear the BSS. */
memset(__bss_start, 0, __bss_end - __bss_start);
/* Set global data pointer. */
gd = &gdata;
board_early_init_f();
preloader_console_init();
if (is_cpu_type(MXC_CPU_MX6Q))
puts("CPU: IMX6Q\n");
else if (is_cpu_type(MXC_CPU_MX6DL))
puts("CPU: IMX6DL\n");
else
puts("CPU: unsupported\n");
printf("SDRAM: %dMB %dbit\n", (16 << (ddrcfg>>8)),
(8 << (ddrcfg & 0xff)));
Really do we need this in SPL ? Is not enough in U-Boot ?
not needed - I used it mainly for debugging and will remove it.
board_init_r(NULL, 0);
+}
Mmhhh...apart the access to the eeprom to get the ram size, this function should be common.
maybe, but I think we should wait to see what other boards come up with SPL support to see what actually ends up being common. An SPL that supports SPI or some of the other boot devices may need to do some additional things.
+/* called from board_init_r() to decide what spl_*_load_image() to call */ +u32 spl_boot_device(void) +{
puts("Boot Device: ");
switch (get_boot_device()) {
case MX6_MMC_BOOT:
printf("uSD\n");
return BOOT_DEVICE_MMC1;
case MX6_NAND_BOOT:
printf("NAND\n");
return BOOT_DEVICE_NAND;
case MX6_SATA_BOOT:
printf("SATA\n");
return BOOT_DEVICE_SATA;
default:
printf("UNKNOWN\n");
return BOOT_DEVICE_NONE;
}
+}
This function (without unneeded printf) should be made common. Feel free to add a spl.c file inside ./arch/arm/imx-common
I'm removing this function and instead using what was 'get_boot_device()' from my other patch for it, which I've moved into arch/arm/imx-common/misc.c. I'm not sure I see the need to display the boot device so I'm removing that as well.
+#if defined(CONFIG_SPL_MMC_SUPPORT) +/* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */ +u32 spl_boot_mode(void) +{
switch (get_boot_device()) {
/* for MMC return either RAW or FAT mode */
case BOOT_DEVICE_MMC1:
+#ifdef CONFIG_SPL_FAT_SUPPORT
return MMCSD_MODE_FAT;
+#else
return MMCSD_MODE_RAW;
+#endif
break;
default:
puts("spl: ERROR: unsupported device\n");
hang();
}
+} +#endif
+void reset_cpu(ulong addr) +{ +} +#endif
Ditto
yes, I'll make this common as well.
diff --git a/board/gateworks/gw_ventana/gw_ventana_spl.cfg b/board/gateworks/gw_ventana/gw_ventana_spl.cfg new file mode 100644 index 0000000..9ab95f5 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.cfg @@ -0,0 +1,29 @@ +/*
- Copyright (C) 2013 Gateworks Corporation
- SPDX-License-Identifier: GPL-2.0+
- Refer doc/README.imximage for more details about how-to configure
- and create imximage boot image
- The syntax is taken as close as possible with the kwbimage
- */
+/* image version */ +IMAGE_VERSION 2
+/*
- Boot Device : one of
- spi, sd, nand, sata
- */
+#ifdef CONFIG_SPI_FLASH +BOOT_FROM spi +#else +BOOT_FROM nand +#endif
+#define __ASSEMBLY__ +#include <config.h> +#include "asm/arch/iomux.h" +#include "asm/arch/crm_regs.h" +#include "clocks.cfg"
Mmhhh...which is the reason to have gw_ventana.cfg and gw_ventana_spl.cfg ?
You need the .cfg file to generate the IVT header only for SPL. It is not required for U-Boot, because the boot ROM has already processed the first i.MX header.
oops - gw_ventana_spl.cfg is not used so I'll remove it
diff --git a/boards.cfg b/boards.cfg index a7be5a3..aa48f89 100644 --- a/boards.cfg +++ b/boards.cfg @@ -320,11 +320,7 @@ Active arm armv7 mx6 freescale mx6qsabreauto Active arm armv7 mx6 freescale mx6sabresd mx6dlsabresd mx6sabresd:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL Fabio Estevam fabio.estevam@freescale.com Active arm armv7 mx6 freescale mx6sabresd mx6qsabresd mx6sabresd:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q Fabio Estevam fabio.estevam@freescale.com Active arm armv7 mx6 freescale mx6slevk mx6slevk mx6slevk:IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL Fabio Estevam fabio.estevam@freescale.com -Active arm armv7 mx6 gateworks gw_ventana gwventanadl gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6DL,DDR_MB=512 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanadl1g gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6DL,DDR_MB=1024 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=512 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq1g gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=1024 Tim Harvey tharvey@gateworks.com -Active arm armv7 mx6 gateworks gw_ventana gwventanaq1gspi gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6Q,DDR_MB=1024,SPI_FLASH Tim Harvey tharvey@gateworks.com +Active arm armv7 mx6 gateworks gw_ventana gwventana gw_ventana:IMX_CONFIG=board/gateworks/gw_ventana/gw_ventana.cfg,MX6QDL,SPL Tim Harvey tharvey@gateworks.com
Nice, only one entry for all of your boards.
yes... considering we currently have 4 baseboards (a fifth on the way), supporting both IMX6DL or IMX6Q on each, and have 2 memory densities (a third on the way) SPL is a must for my sanity to eliminate what would be something like 5*2*3 various build-time configurations.
The dynamic ddr configuration functionality I'm proposing helps out tremendously as well because the DDR3 calibration and testing I've done tells me that each board design (varied layout between SoC and DDR3) needs its own calibration values due to propagation delays and IMX6Q/D vs IMX6DL/SOLO need different calibration values on each board as well. This can all be handled with minimal tables and easily configured at runtime via baseboard detection, cpu detection, and memory density information.
<snip>
diff --git a/include/configs/gw_ventana.h b/include/configs/gw_ventana.h index 3398390..f6dc52a 100644 --- a/include/configs/gw_ventana.h +++ b/include/configs/gw_ventana.h @@ -7,6 +7,17 @@ #ifndef __CONFIG_H #define __CONFIG_H
+/* SPL */ +#define CONFIG_SPL_NAND_SUPPORT +/* +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SPL_SATA_SUPPORT +#define CONFIG_SPL_FAT_SUPPORT +*/ +/* Location in NAND to read U-Boot from */ +#define CONFIG_SYS_NAND_U_BOOT_OFFS (14 * 1024 * 1024)
This is ok - it is your decision where to put it.
May I ask why do you need 14 MB at the beginning ? It seems you lose a lot of place. NAND is cheap nowadays, but...
it was perhaps a poor decision I made early on when I was following too much of the reference design without understanding all the details. They used a 16MB area in NAND for the bootstreams so that is what I used as well. I worked through the calculation once and the 16MB wasn't all that crazy considering at the time I was wanting enough room to support a 1MB u-boot. When you add the blocks and redundant blocks for FCB/DBBT (default is to have 2 copies of these), then double the bootloader size (because IMX BOOT ROM supports 2 firmware images for redundancy), and factor in 20% headroom to allow for bad blocks, the 16MB wasn't all that crazy. Now that I'm talking about using 14MB for a <64KB SPL image, its overkill for sure.
I don't want to impose a partition layout change on our existing users that I want to update to the SPL bootloader (with all the improved DDR3 calibration values) so I figure we'll put u-boot.img in the last 2MB of the 16MB partition for the 'bootloader' and leave the first 14MB for SPL to be flashed according to the IMX6 BOOT ROM.
+#include "imx6_spl.h" /* common IMX6 SPL configuration */ #include "mx6_common.h" #define CONFIG_MX6 #define CONFIG_DISPLAY_CPUINFO /* display cpu info */ @@ -242,7 +253,7 @@ "mtdparts=nor:512k(uboot),64k(env),2m(kernel),-(rootfs)" #else #define MTDIDS_DEFAULT "nand0=nand" -#define MTDPARTS_DEFAULT "mtdparts=nand:16m(uboot),1m(env),-(rootfs)" +#define MTDPARTS_DEFAULT "mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs)"
and I'll be reverting that last change as well and leaving the original 16M partition for the 'bootloader' meaning the 14MB area flashed by kobs-ng according to the IMX6 BOOT ROM requirements for NAND boot as well as the 2MB area I'm reserving for u-boot.img.
If I were to split the partitions like the above change, it will cause some grief for existing users that are using the 3.0.35 (non device-tree) vendor kernel that has the mtd partitions hard coded in the board support. Instead, I decided to patch the kobs-ng application used to flash the SPL so that it can be passed a max size to use within /dev/mtd0 and users that need to upgrade to the SPL bootloader will need to use that patched kobs-ng to flash the SPL to the first 14MB, then use std mtd utils to flash u-boot.img in the area between 14M and 16M.
Don't forget, at some point soon I hope to add some functionality to u-boot to flash the SPL portion to nand (the way kobs-ng does) so that you don't need to boot to linux and use kobs-ng or use our JTAG tool.
Thanks for the reviews. I have a few more things to catch up on, but hope to post a v2 by the end of the week or early next week.
Regards,
Tim

Hi Tim,
On 24/04/2014 10:06, Tim Harvey wrote:
+/* configure mx6 mmdc io registers */ +struct mx6_mmdc_ioregs mmdc_ioregs = {
/* DDR3 */
.mmdc_grp_ddr_type = 0x000c0000,
/* disable DDR pullups */
.mmdc_grp_ddrpke = 0x00000000,
/* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */
.mmdc_dram_sdclk_0 = 0x00020030,
.mmdc_dram_sdclk_1 = 0x00020030,
.mmdc_dram_cas = 0x00020030,
.mmdc_dram_ras = 0x00020030,
.mmdc_dram_reset = 0x00020030,
/* ADDR[00:16], SDBA[0:1]: 40 ohm */
.mmdc_grp_addds = 0x00000030,
/* SDCKE[0:1]: 100k pull-up */
.mmdc_dram_sdcke0 = 0x00003000,
.mmdc_dram_sdcke1 = 0x00003000,
/* SDBA2: pull-up disabled */
.mmdc_dram_sdba2 = 0x00000000,
/* SDODT[0:1]: 100k pull-up, 40 ohm */
.mmdc_dram_sdodt0 = 0x00003030,
.mmdc_dram_sdodt1 = 0x00003030,
/* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */
.mmdc_grp_ctlds = 0x00000030,
/* SDQS[0:7]: Differential input, 40 ohm */
.mmdc_ddrmode_ctl = 0x00020000,
.mmdc_dram_sdqs0 = 0x00000030,
.mmdc_dram_sdqs1 = 0x00000030,
.mmdc_dram_sdqs2 = 0x00000030,
.mmdc_dram_sdqs3 = 0x00000030,
.mmdc_dram_sdqs4 = 0x00000030,
.mmdc_dram_sdqs5 = 0x00000030,
.mmdc_dram_sdqs6 = 0x00000030,
.mmdc_dram_sdqs7 = 0x00000030,
/* DATA[00:63]: Differential input, 40 ohm */
.mmdc_grp_ddrmode = 0x00020000,
.mmdc_grp_b0ds = 0x00000030,
.mmdc_grp_b1ds = 0x00000030,
.mmdc_grp_b2ds = 0x00000030,
.mmdc_grp_b3ds = 0x00000030,
.mmdc_grp_b4ds = 0x00000030,
.mmdc_grp_b5ds = 0x00000030,
.mmdc_grp_b6ds = 0x00000030,
.mmdc_grp_b7ds = 0x00000030,
/* DQM[0:7]: Differential input, 40 ohm */
.mmdc_dram_dqm0 = 0x00020030,
.mmdc_dram_dqm1 = 0x00020030,
.mmdc_dram_dqm2 = 0x00020030,
.mmdc_dram_dqm3 = 0x00020030,
.mmdc_dram_dqm4 = 0x00020030,
.mmdc_dram_dqm5 = 0x00020030,
.mmdc_dram_dqm6 = 0x00020030,
.mmdc_dram_dqm7 = 0x00020030,
+};
I will suggest you move these structure in a separate file. It is then easier for a board developer to understand what is very board specific.
hmmm... they are all very board specific but ok.
Well, I am noy saying to move it outside board/gateworks/gw_ventana. My proposal is more as to signalize how to add SPL support for a new board. Anyway, I agree it is a personal taste.
not needed - I used it mainly for debugging and will remove it.
board_init_r(NULL, 0);
+}
Mmhhh...apart the access to the eeprom to get the ram size, this function should be common.
maybe, but I think we should wait to see what other boards come up with SPL support to see what actually ends up being common. An SPL that supports SPI or some of the other boot devices may need to do some additional things.
Agree, this makes sense. We can do it later.
yes... considering we currently have 4 baseboards (a fifth on the way), supporting both IMX6DL or IMX6Q on each, and have 2 memory densities (a third on the way) SPL is a must for my sanity to eliminate what would be something like 5*2*3 various build-time configurations.
The dynamic ddr configuration functionality I'm proposing helps out tremendously as well because the DDR3 calibration and testing I've done tells me that each board design (varied layout between SoC and DDR3) needs its own calibration values due to propagation delays and IMX6Q/D vs IMX6DL/SOLO need different calibration values on each board as well. This can all be handled with minimal tables and easily configured at runtime via baseboard detection, cpu detection, and memory density information.
Very nice.
+#define CONFIG_SYS_NAND_U_BOOT_OFFS (14 * 1024 * 1024)
This is ok - it is your decision where to put it.
May I ask why do you need 14 MB at the beginning ? It seems you lose a lot of place. NAND is cheap nowadays, but...
it was perhaps a poor decision I made early on when I was following too much of the reference design without understanding all the details. They used a 16MB area in NAND for the bootstreams so that is what I used as well. I worked through the calculation once and the 16MB wasn't all that crazy considering at the time I was wanting enough room to support a 1MB u-boot. When you add the blocks and redundant blocks for FCB/DBBT (default is to have 2 copies of these), then double the bootloader size (because IMX BOOT ROM supports 2 firmware images for redundancy), and factor in 20% headroom to allow for bad blocks, the 16MB wasn't all that crazy. Now that I'm talking about using 14MB for a <64KB SPL image, its overkill for sure.
I don't want to impose a partition layout change on our existing users that I want to update to the SPL bootloader (with all the improved DDR3 calibration values) so I figure we'll put u-boot.img in the last 2MB of the 16MB partition for the 'bootloader' and leave the first 14MB for SPL to be flashed according to the IMX6 BOOT ROM.
ok, thanks for explanation
+#include "imx6_spl.h" /* common IMX6 SPL configuration */ #include "mx6_common.h" #define CONFIG_MX6 #define CONFIG_DISPLAY_CPUINFO /* display cpu info */ @@ -242,7 +253,7 @@ "mtdparts=nor:512k(uboot),64k(env),2m(kernel),-(rootfs)" #else #define MTDIDS_DEFAULT "nand0=nand" -#define MTDPARTS_DEFAULT "mtdparts=nand:16m(uboot),1m(env),-(rootfs)" +#define MTDPARTS_DEFAULT "mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs)"
and I'll be reverting that last change as well and leaving the original 16M partition for the 'bootloader' meaning the 14MB area flashed by kobs-ng according to the IMX6 BOOT ROM requirements for NAND boot as well as the 2MB area I'm reserving for u-boot.img.
If I were to split the partitions like the above change, it will cause some grief for existing users that are using the 3.0.35 (non device-tree) vendor kernel that has the mtd partitions hard coded in the board support. Instead, I decided to patch the kobs-ng application used to flash the SPL so that it can be passed a max size to use within /dev/mtd0 and users that need to upgrade to the SPL bootloader will need to use that patched kobs-ng to flash the SPL to the first 14MB, then use std mtd utils to flash u-boot.img in the area between 14M and 16M.
Don't forget, at some point soon I hope to add some functionality to u-boot to flash the SPL portion to nand (the way kobs-ng does) so that you don't need to boot to linux and use kobs-ng or use our JTAG tool.
This will be a great improvement ! Thanks for working on this issue.
Best regards, Stefano

Hi Tim!
BTW: Thanks for all your work on this. Great work and really appreciated.
Just a quick note:
On 24.04.2014 10:06, Tim Harvey wrote:
<big snip>
If I were to split the partitions like the above change, it will cause some grief for existing users that are using the 3.0.35 (non device-tree) vendor kernel that has the mtd partitions hard coded in the board support. Instead, I decided to patch the kobs-ng application used to flash the SPL so that it can be passed a max size to use within /dev/mtd0 and users that need to upgrade to the SPL bootloader will need to use that patched kobs-ng to flash the SPL to the first 14MB, then use std mtd utils to flash u-boot.img in the area between 14M and 16M.
Don't forget, at some point soon I hope to add some functionality to u-boot to flash the SPL portion to nand (the way kobs-ng does) so that you don't need to boot to linux and use kobs-ng or use our JTAG tool.
For such a functionality it might make sense to take a look at what has been recently added to barebox:
http://comments.gmane.org/gmane.comp.boot-loaders.barebox/12612 http://comments.gmane.org/gmane.comp.boot-loaders.barebox/12856
Thanks, Stefan
participants (9)
-
Eric Nelson
-
Igor Grinberg
-
Masahiro Yamada
-
Nikita Kiryanov
-
Otavio Salvador
-
Scott Wood
-
Stefan Roese
-
Stefano Babic
-
Tim Harvey