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

This series adds some necessary framework for IMX6 SPL support. The series includes support for NAND SPL and has been tested with MMC as well. I have tested this on five differing Ventana baseboards with a variety of memory (32bit 512MB, 32bit 1024MB, 64bit 1024MB) and CPU configurations (IMX6Q, IMX6DL, IMX6S).
v2: - use compatible linker script instead of creating new one - remove structure passing data from SPL to u-boot - remove dependence on mtdpart, mtdcore, nand_util, nand_ecc, nand_base and nand_bbt to bring SPL down in size. This reduced codesize by about 32k where now mxs_spl_nand is about 12k total - adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD - move boot dev detection into imx-common/spl.c - move macros for using pinmux array into iomux-v3.h - remove missing/unnecessary include - revert mtdparts change - use get_ram_size() to detect memory - add support for MX6SOLO and MX6DUAL - set CS0_END for 4GB so get_ram_size() works - updated DDR3 calibration values for ventana boards - fixed build issue - only compile spl if doing spl build - fixed line length issue in README - remove CONFIG_SPL* conditions and conditionally compile instead - removed prints for CPU type and DRAM size/width - uboot will print these l - removed unused gw_ventana_spl.cfg - use common read_eeprom function - added MMC support to SPL - added Masahiro Yamada's boot mode consolidation patch http://patchwork.ozlabs.org/patch/341817 and rebase on top of it
Masahiro Yamada (1): spl: consolidate arch/arm/include/asm/arch-*/spl.h
Tim Harvey (11): SPL: NAND: remove CONFIG_SYS_NAND_PAGE_SIZE SPL: NAND: add support for mxs nand MX6: add common SPL configuration MX6: add boot device support for SPL IMX: add comments and remove unused struct fields MX6: add structs for mmdc and ddr iomux registers MX6: add mmdc configuration for MX6Q/MX6DL IMX: add additional function for pinmux using an array imx: ventana: split read_eeprom into standalone file imx: ventana: auto-configure for IMX6Q vs IMX6DL imx: ventana: switch to SPL
arch/arm/cpu/arm720t/tegra-common/spl.c | 2 +- arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 469 ++++++++++++++++++++++ arch/arm/imx-common/Makefile | 1 + arch/arm/imx-common/cpu.c | 16 +- arch/arm/imx-common/iomux-v3.c | 19 +- arch/arm/imx-common/spl.c | 79 ++++ arch/arm/include/asm/arch-at91/spl.h | 24 -- arch/arm/include/asm/arch-davinci/spl.h | 16 - arch/arm/include/asm/arch-mx35/spl.h | 22 -- arch/arm/include/asm/arch-mx5/spl.h | 13 - arch/arm/include/asm/arch-mx6/mx6-ddr.h | 231 +++++++++++ arch/arm/include/asm/arch-tegra114/spl.h | 22 -- arch/arm/include/asm/arch-tegra124/spl.h | 13 - arch/arm/include/asm/arch-tegra20/spl.h | 12 - arch/arm/include/asm/arch-tegra30/spl.h | 12 - arch/arm/include/asm/imx-common/iomux-v3.h | 15 + arch/arm/include/asm/spl.h | 20 + board/denx/m53evk/m53evk.c | 2 +- board/gateworks/gw_ventana/Makefile | 3 +- board/gateworks/gw_ventana/README | 92 +++-- board/gateworks/gw_ventana/eeprom.c | 89 +++++ board/gateworks/gw_ventana/gw_ventana.c | 591 +++++++++++++++------------- board/gateworks/gw_ventana/gw_ventana.cfg | 15 - board/gateworks/gw_ventana/gw_ventana_spl.c | 407 +++++++++++++++++++ board/gateworks/gw_ventana/ventana_eeprom.h | 11 + boards.cfg | 6 +- common/spl/spl_nand.c | 2 +- drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/mxs_nand_spl.c | 239 +++++++++++ include/configs/gw_ventana.h | 11 + include/configs/imx6_spl.h | 71 ++++ 32 files changed, 2050 insertions(+), 477 deletions(-) create mode 100644 arch/arm/cpu/armv7/mx6/ddr.c create mode 100644 arch/arm/imx-common/spl.c delete mode 100644 arch/arm/include/asm/arch-at91/spl.h delete mode 100644 arch/arm/include/asm/arch-davinci/spl.h delete mode 100644 arch/arm/include/asm/arch-mx35/spl.h delete mode 100644 arch/arm/include/asm/arch-mx5/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra114/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra124/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra20/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra30/spl.h create mode 100644 board/gateworks/gw_ventana/eeprom.c create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.c create mode 100644 drivers/mtd/nand/mxs_nand_spl.c 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.
Cc: Scott Wood scottwood@freescale.com Signed-off-by: Tim Harvey tharvey@gateworks.com Acked-by: Stefano Babic sbabic@denx.de Acked-by: Scott Wood scottwood@freescale.com --- v2: - cc Scott Wood scottwood@freescale.com on this - Acked-by: Stefano Babic sbabic@denx.de - Acked-by: Scott Wood scottwood@freescale.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);

This utilizes existing mxs_nand support layer to provide a method to load an image off nand for SPL. The flash device will be detected in order to support multiple flash devices instead of having layout hard coded at build time.
Cc: Scott Wood scottwood@freescale.com Signed-off-by: Tim Harvey tharvey@gateworks.com --- v2: - remove dependence on mtdpart, mtdcore, nand_util, nand_ecc, nand_base and nand_bbt to bring SPL down in size. This reduced codesize by about 32k where now mxs_spl_nand is about 12k total. --- drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/mxs_nand_spl.c | 239 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 drivers/mtd/nand/mxs_nand_spl.c
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 02b149c..de5b461 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -65,5 +65,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..82491a4 --- /dev/null +++ b/drivers/mtd/nand/mxs_nand_spl.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2014 Gateworks Corporation + * Author: Tim Harvey tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <nand.h> +#include <malloc.h> + +static nand_info_t mtd; +static struct nand_chip nand_chip; + +static void mxs_nand_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd->priv; + int ctrl = NAND_NCE | NAND_CTRL_CLE | NAND_CTRL_CHANGE; + u32 timeo, time_start; + + /* write out the command to the device */ + chip->cmd_ctrl(mtd, command, ctrl); + + /* Address cycle, when necessary */ + ctrl = NAND_NCE | NAND_CTRL_ALE | NAND_CTRL_CHANGE; + /* Serially input address */ + if (column != -1) { + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; + chip->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + chip->cmd_ctrl(mtd, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->cmd_ctrl(mtd, page_addr, ctrl); + chip->cmd_ctrl(mtd, page_addr >> 8, NAND_NCE | NAND_ALE); + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) + chip->cmd_ctrl(mtd, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + if (command == NAND_CMD_READ0) { + chip->cmd_ctrl(mtd, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + } + + /* wait for nand ready */ + ndelay(100); + timeo = (CONFIG_SYS_HZ * 20) / 1000; + time_start = get_timer(0); + while (get_timer(time_start) < timeo) { + if (chip->dev_ready(mtd)) + break; + } +} + +static int mxs_flash_ident(struct mtd_info *mtd) +{ + register struct nand_chip *chip = mtd->priv; + int i; + u8 mfg_id, dev_id; + u8 id_data[8]; + struct nand_onfi_params *p = &chip->onfi_params; + + /* Reset the chip */ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + mfg_id = chip->read_byte(mtd); + dev_id = chip->read_byte(mtd); + + /* Try again to make sure */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + for (i = 0; i < 8; i++) + id_data[i] = chip->read_byte(mtd); + if (id_data[0] != mfg_id || id_data[1] != dev_id) { + printf("second ID read did not match"); + return -1; + } + debug("0x%02x:0x%02x ", mfg_id, dev_id); + + /* read ONFI */ + chip->onfi_version = 0; + chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); + if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || + chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') { + return -2; + } + + /* we have ONFI, probe it */ + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); + chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + mtd->name = p->model; + mtd->writesize = le32_to_cpu(p->byte_per_page); + mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; + mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); + chip->chipsize = le32_to_cpu(p->blocks_per_lun); + chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; + /* Calculate the address shift from the page size */ + chip->page_shift = ffs(mtd->writesize) - 1; + chip->phys_erase_shift = ffs(mtd->erasesize) - 1; + /* Convert chipsize to number of pages per chip -1 */ + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + chip->badblockbits = 8; + + debug("erasesize=%d (>>%d)\n", mtd->erasesize, chip->phys_erase_shift); + debug("writesize=%d (>>%d)\n", mtd->writesize, chip->page_shift); + debug("oobsize=%d\n", mtd->oobsize); + debug("chipsize=%lld\n", chip->chipsize); + + return 0; +} + +static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page) +{ + register struct nand_chip *chip = mtd->priv; + int ret; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); + ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page); + if (ret < 0) { + printf("read_page failed %d\n", ret); + return -1; + } + return 0; +} + +static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt) +{ + register struct nand_chip *chip = mtd->priv; + unsigned int block = offs >> chip->phys_erase_shift; + unsigned int page = offs >> chip->page_shift; + + debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block, + page); + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + memset(chip->oob_poi, 0, mtd->oobsize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return (chip->oob_poi[0] != 0xff); +} + +/* setup mtd and nand structs and init mxs_nand driver */ +static int mxs_nand_init(void) +{ + /* return if already initalized */ + if (nand_chip.numchips) + return 0; + + /* init mxs nand driver */ + board_nand_init(&nand_chip); + mtd.priv = &nand_chip; + /* set mtd functions */ + nand_chip.cmdfunc = mxs_nand_command; + nand_chip.numchips = 1; + + /* identify flash device */ + puts("NAND : "); + if (mxs_flash_ident(&mtd)) { + printf("Failed to identify\n"); + return -1; + } + + /* allocate and initialize buffers */ + nand_chip.buffers = memalign(ARCH_DMA_MINALIGN, + sizeof(*nand_chip.buffers)); + nand_chip.oob_poi = nand_chip.buffers->databuf + mtd.writesize; + /* setup flash layout (does not scan as we override that) */ + mtd.size = nand_chip.chipsize; + nand_chip.scan_bbt(&mtd); + + printf("%llu MiB\n", (mtd.size / (1024 * 1024))); + return 0; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) +{ + register struct nand_chip *chip; + unsigned int page; + unsigned int nand_page_per_block; + unsigned int sz = 0; + + if (mxs_nand_init()) + return -1; + chip = mtd.priv; + page = offs >> chip->page_shift; + nand_page_per_block = mtd.erasesize / mtd.writesize; + + debug("%s offset:0x%08x len:%d page:%d\n", __func__, offs, size, page); + + size = roundup(size, mtd.writesize); + while (sz < size) { + if (mxs_read_page_ecc(&mtd, buf, page) < 0) + return -1; + sz += mtd.writesize; + offs += mtd.writesize; + page++; + buf += mtd.writesize; + + /* + * Check if we have crossed a block boundary, and if so + * check for bad block. + */ + if (!(page % nand_page_per_block)) { + /* + * Yes, new block. See if this block is good. If not, + * loop until we find a good block. + */ + while (is_badblock(&mtd, offs, 1)) { + page = page + nand_page_per_block; + /* Check i we've reached the end of flash. */ + if (page >= mtd.size >> chip->page_shift) + return -1; + } + } + } + + return 0; +} + +int nand_default_bbt(struct mtd_info *mtd) +{ + return 0; +} + +void nand_init(void) +{ +} + +void nand_deselect(void) +{ +} +

On Mon, 2014-04-28 at 13:17 -0700, Tim Harvey wrote:
+static void mxs_nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
+{
- register struct nand_chip *chip = mtd->priv;
- int ctrl = NAND_NCE | NAND_CTRL_CLE | NAND_CTRL_CHANGE;
- u32 timeo, time_start;
- /* write out the command to the device */
- chip->cmd_ctrl(mtd, command, ctrl);
- /* Address cycle, when necessary */
- ctrl = NAND_NCE | NAND_CTRL_ALE | NAND_CTRL_CHANGE;
- /* Serially input address */
- if (column != -1) {
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
What happened to NAND_NCE?
It looks like the cmd_ctrl in nand_mxs.c doesn't care about NAND_MCE at all, so there's no functional impact, but either use it consistently or don't use it at all.
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
Why not pass the ctrl flags directly to cmd_ctrl as you do in most of the rest of the function? nand_mxs.c doesn't even look at NAND_CTRL_CHANGE.
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) +{
- register struct nand_chip *chip;
Why "register"?
if (!(page % nand_page_per_block)) {
/*
* Yes, new block. See if this block is good. If not,
* loop until we find a good block.
*/
while (is_badblock(&mtd, offs, 1)) {
page = page + nand_page_per_block;
/* Check i we've reached the end of flash. */
if (page >= mtd.size >> chip->page_shift)
return -1;
Why -1 rather than a real error value?
-Scott

On Fri, May 2, 2014 at 1:56 PM, Scott Wood scottwood@freescale.com wrote:
Hi Scott,
On Mon, 2014-04-28 at 13:17 -0700, Tim Harvey wrote:
+static void mxs_nand_command(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
+{
register struct nand_chip *chip = mtd->priv;
int ctrl = NAND_NCE | NAND_CTRL_CLE | NAND_CTRL_CHANGE;
u32 timeo, time_start;
/* write out the command to the device */
chip->cmd_ctrl(mtd, command, ctrl);
/* Address cycle, when necessary */
ctrl = NAND_NCE | NAND_CTRL_ALE | NAND_CTRL_CHANGE;
/* Serially input address */
if (column != -1) {
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
What happened to NAND_NCE?
It looks like the cmd_ctrl in nand_mxs.c doesn't care about NAND_MCE at all, so there's no functional impact, but either use it consistently or don't use it at all.
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
chip->cmd_ctrl(mtd, column >> 8, ctrl);
}
Why not pass the ctrl flags directly to cmd_ctrl as you do in most of the rest of the function? nand_mxs.c doesn't even look at NAND_CTRL_CHANGE.
I'll simplify using only what nand_mxs.c pays attention to (NAND_ALE, NAND_CLE), remove the ctrl var and repost
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) +{
register struct nand_chip *chip;
Why "register"?
cut-n-paste code from nand_base.c - will remove
if (!(page % nand_page_per_block)) {
/*
* Yes, new block. See if this block is good. If not,
* loop until we find a good block.
*/
while (is_badblock(&mtd, offs, 1)) {
page = page + nand_page_per_block;
/* Check i we've reached the end of flash. */
if (page >= mtd.size >> chip->page_shift)
return -1;
Why -1 rather than a real error value?
probably from the example I used from drivers/mtd/nand/mxc_nand_spl.c. The calling functions don't appear to do any error checking, but I'll replace it with -ENOMEM and -ENODEV if mxs_nand_init() fails.
Thanks for the review!
Tim
-Scott

Add a common header which can hopefully be shared amon imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com --- v2: - adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD --- include/configs/imx6_spl.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 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..20078cc --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 Gateworks Corporation + * 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 + +/* + * see Figure 8-3 in IMX6DQ/IMX6SDL Reference manuals: + * - IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0091FFFF (IMX6SLD) + * - IMX6DQ has 2x IRAM of IMX6SLD but we intend to support IMX6SLD as well + * - BOOT ROM stack is at 0x0091FFB8 + * - if icache/dcache is enabled (eFuse/strapping controlled) then the + * IMX BOOT ROM will setup MMU table at 0x00918000, therefore we need to + * fit between 0x00907000 and 0x00918000. + * - Additionally the BOOT ROM loads what they consider the firmware image + * which consists of a 4K header in front of us that contains the IVT, DCD + * and some padding thus 'our' max size is really 0x00908000 - 0x00918000 + * or 64KB + */ +#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/omap-common/u-boot-spl.lds" +#define CONFIG_SPL_TEXT_BASE 0x00908000 +#define CONFIG_SPL_MAX_SIZE (64 * 1024) +#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7" +#define CONFIG_SPL_STACK 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_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/28/2014 01:17 PM, Tim Harvey wrote:
Add a common header which can hopefully be shared amon imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD
include/configs/imx6_spl.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 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..20078cc --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,71 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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
+/*
- see Figure 8-3 in IMX6DQ/IMX6SDL Reference manuals:
s/IMX6SLD/IMX6SDL/g
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0091FFFF (IMX6SLD)
- IMX6DQ has 2x IRAM of IMX6SLD but we intend to support IMX6SLD as well
... I was about to complain about the use of IMX6SLD (the nomenclature i.MX6DL/S seems more common), but the RM __is__ named SDL...
Regards,
Eric

Hi,
On 04/29/14 07:14, Eric Nelson wrote:
Hi Tim,
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add a common header which can hopefully be shared amon imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD
include/configs/imx6_spl.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 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..20078cc --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,71 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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
+/*
- see Figure 8-3 in IMX6DQ/IMX6SDL Reference manuals:
s/IMX6SLD/IMX6SDL/g
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0091FFFF (IMX6SLD)
- IMX6DQ has 2x IRAM of IMX6SLD but we intend to support IMX6SLD as well
... I was about to complain about the use of IMX6SLD (the nomenclature i.MX6DL/S seems more common), but the RM __is__ named SDL...
SDL stands for Solo/Dual Lite, so SLD is plain wrong... (Solo Lite and Dual are so different...)

On Mon, Apr 28, 2014 at 11:37 PM, Igor Grinberg grinberg@compulab.co.il wrote:
Hi,
On 04/29/14 07:14, Eric Nelson wrote:
Hi Tim,
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add a common header which can hopefully be shared amon imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD
include/configs/imx6_spl.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 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..20078cc --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,71 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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
+/*
- see Figure 8-3 in IMX6DQ/IMX6SDL Reference manuals:
s/IMX6SLD/IMX6SDL/g
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0091FFFF (IMX6SLD)
- IMX6DQ has 2x IRAM of IMX6SLD but we intend to support IMX6SLD as well
... I was about to complain about the use of IMX6SLD (the nomenclature i.MX6DL/S seems more common), but the RM __is__ named SDL...
SDL stands for Solo/Dual Lite, so SLD is plain wrong... (Solo Lite and Dual are so different...)
-- Regards, Igor.
Igor / Eric,
Yes this was definitely a typo - no idea how I kept making the same typo over and over again... late nights!
I'll fix this for the next revision and refer to the CPU types as 'IMX6DQ' and 'IMX6SDL'.
Please let me know if there is anything else you see that needs to be discussed.
Tim

Hi Tim,
On 28/04/2014 22:17, Tim Harvey wrote:
Add a common header which can hopefully be shared amon imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD
include/configs/imx6_spl.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 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..20078cc --- /dev/null +++ b/include/configs/imx6_spl.h @@ -0,0 +1,71 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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
+/*
- see Figure 8-3 in IMX6DQ/IMX6SDL Reference manuals:
- IMX6 OCRAM (IRAM) is from 0x00907000 to 0x0091FFFF (IMX6SLD)
- IMX6DQ has 2x IRAM of IMX6SLD but we intend to support IMX6SLD as well
- BOOT ROM stack is at 0x0091FFB8
- if icache/dcache is enabled (eFuse/strapping controlled) then the
- IMX BOOT ROM will setup MMU table at 0x00918000, therefore we need to
- fit between 0x00907000 and 0x00918000.
- Additionally the BOOT ROM loads what they consider the firmware image
- which consists of a 4K header in front of us that contains the IVT, DCD
- and some padding thus 'our' max size is really 0x00908000 - 0x00918000
- or 64KB
- */
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/omap-common/u-boot-spl.lds" +#define CONFIG_SPL_TEXT_BASE 0x00908000 +#define CONFIG_SPL_MAX_SIZE (64 * 1024) +#define CONFIG_SPL_START_S_PATH "arch/arm/cpu/armv7" +#define CONFIG_SPL_STACK 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_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
I generally agree with the idea having a common setup - this simplifies porting of new boards to SPL !
Apart the small typos found by Eric/Igor:
Acked-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

On 28/04/14 23:17, Tim Harvey wrote:
Add a common header which can hopefully be shared amon imx6 SPL users
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- adjust CONFIG_SPL_TEXT_BASE, CONFIG_SPL_STACK and CONFIG_SPL_MAX_SIZE to accomodate the IMX6SOLO/DUALLITE which have half the iRAM of the IMX6DUAL/IMX6QUAD
Aside from the typos, Acked-by: Nikita Kiryanov nikita@compulab.co.il
-- Regards, Nikita Kiryanov

From: Masahiro Yamada yamada.m@jp.panasonic.com
arch/arm/include/asm/spl.h requires all SoCs to have arch/arm/include/asm/arch-*/spl.h.
But many of them just define BOOT_DEVICE_* macros.
Those macros are used in the "switch (boot_device) { ... }" statement in common/spl/spl.c.
So they should not be archtecture specific, but be described as a simpile enumeration.
This commit merges most of arch/arm/include/asm/arch-*/spl.h into arch/arm/include/asm/spl.h.
With a little more effort, arch-zynq/spl.h and arch-socfpga/spl.h will be merged, while I am not sure about OMAP and Exynos.
Signed-off-by: Masahiro Yamada yamada.m@jp.panasonic.com Cc: Tom Rini trini@ti.com Cc: Michal Simek michal.simek@xilinx.com Cc: Andreas Bießmann andreas.devel@googlemail.com Cc: Stephen Warren swarren@nvidia.com Cc: Tom Warren twarren@nvidia.com CC: Stefano Babic sbabic@denx.de CC: Minkyu Kang mk7.kang@samsung.com Cc: Dinh Nguyen dinguyen@altera.com Acked-by: Andreas Bießmann andreas.devel@googlemail.com Acked-by: Michal Simek monstr@monstr.eu Acked-by: Stefano Babic sbabic@denx.de Acked-by: Stephen Warren swarren@nvidia.com Acked-by: Tim Harvey tharvey@gateworks.com Tested-by: Bo Shen voice.shen@atmel.com [on sama5d3xek board for at91 part] Acked-by: Stephen Warren swarren@nvidia.com Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/cpu/arm720t/tegra-common/spl.c | 2 +- arch/arm/include/asm/arch-at91/spl.h | 24 ------------------------ arch/arm/include/asm/arch-davinci/spl.h | 16 ---------------- arch/arm/include/asm/arch-mx35/spl.h | 22 ---------------------- arch/arm/include/asm/arch-mx5/spl.h | 13 ------------- arch/arm/include/asm/arch-tegra114/spl.h | 22 ---------------------- arch/arm/include/asm/arch-tegra124/spl.h | 13 ------------- arch/arm/include/asm/arch-tegra20/spl.h | 12 ------------ arch/arm/include/asm/arch-tegra30/spl.h | 12 ------------ arch/arm/include/asm/spl.h | 20 ++++++++++++++++++++ board/denx/m53evk/m53evk.c | 2 +- 11 files changed, 22 insertions(+), 136 deletions(-) delete mode 100644 arch/arm/include/asm/arch-at91/spl.h delete mode 100644 arch/arm/include/asm/arch-davinci/spl.h delete mode 100644 arch/arm/include/asm/arch-mx35/spl.h delete mode 100644 arch/arm/include/asm/arch-mx5/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra114/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra124/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra20/spl.h delete mode 100644 arch/arm/include/asm/arch-tegra30/spl.h
diff --git a/arch/arm/cpu/arm720t/tegra-common/spl.c b/arch/arm/cpu/arm720t/tegra-common/spl.c index 5171a8f..8147806 100644 --- a/arch/arm/cpu/arm720t/tegra-common/spl.c +++ b/arch/arm/cpu/arm720t/tegra-common/spl.c @@ -14,7 +14,7 @@ #include <asm/arch/pinmux.h> #include <asm/arch/tegra.h> #include <asm/arch-tegra/board.h> -#include <asm/arch/spl.h> +#include <asm/spl.h> #include "cpu.h"
void spl_board_init(void) diff --git a/arch/arm/include/asm/arch-at91/spl.h b/arch/arm/include/asm/arch-at91/spl.h deleted file mode 100644 index d8a87da..0000000 --- a/arch/arm/include/asm/arch-at91/spl.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2013 Atmel Corporation - * Bo Shen voice.shen@atmel.com - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -enum { - BOOT_DEVICE_NONE, -#ifdef CONFIG_SYS_USE_MMC - BOOT_DEVICE_MMC1, - BOOT_DEVICE_MMC2, - BOOT_DEVICE_MMC2_2, -#elif CONFIG_SYS_USE_NANDFLASH - BOOT_DEVICE_NAND, -#elif CONFIG_SYS_USE_SERIALFLASH - BOOT_DEVICE_SPI, -#endif -}; - -#endif diff --git a/arch/arm/include/asm/arch-davinci/spl.h b/arch/arm/include/asm/arch-davinci/spl.h deleted file mode 100644 index 5afe0d4..0000000 --- a/arch/arm/include/asm/arch-davinci/spl.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * (C) Copyright 2012 - * Texas Instruments, <www.ti.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -#define BOOT_DEVICE_NAND 1 -#define BOOT_DEVICE_SPI 2 -#define BOOT_DEVICE_MMC1 3 -#define BOOT_DEVICE_MMC2 4 /* dummy */ -#define BOOT_DEVICE_MMC2_2 5 /* dummy */ - -#endif diff --git a/arch/arm/include/asm/arch-mx35/spl.h b/arch/arm/include/asm/arch-mx35/spl.h deleted file mode 100644 index d0efec2..0000000 --- a/arch/arm/include/asm/arch-mx35/spl.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * (C) Copyright 2012 - * Texas Instruments, <www.ti.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -#define BOOT_DEVICE_NONE 0 -#define BOOT_DEVICE_XIP 1 -#define BOOT_DEVICE_XIPWAIT 2 -#define BOOT_DEVICE_NAND 3 -#define BOOT_DEVICE_ONENAND 4 -#define BOOT_DEVICE_MMC1 5 -#define BOOT_DEVICE_MMC2 6 -#define BOOT_DEVICE_MMC2_2 7 -#define BOOT_DEVICE_NOR 8 -#define BOOT_DEVICE_I2C 9 -#define BOOT_DEVICE_SPI 10 - -#endif diff --git a/arch/arm/include/asm/arch-mx5/spl.h b/arch/arm/include/asm/arch-mx5/spl.h deleted file mode 100644 index 20c6cae..0000000 --- a/arch/arm/include/asm/arch-mx5/spl.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2013 Marek Vasut marex@denx.de - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __ASM_ARCH_SPL_H__ -#define __ASM_ARCH_SPL_H__ - -#define BOOT_DEVICE_NONE 0 -#define BOOT_DEVICE_NAND 1 - -#endif /* __ASM_ARCH_SPL_H__ */ diff --git a/arch/arm/include/asm/arch-tegra114/spl.h b/arch/arm/include/asm/arch-tegra114/spl.h deleted file mode 100644 index ebb16fe..0000000 --- a/arch/arm/include/asm/arch-tegra114/spl.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ - -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -#define BOOT_DEVICE_RAM 1 - -#endif diff --git a/arch/arm/include/asm/arch-tegra124/spl.h b/arch/arm/include/asm/arch-tegra124/spl.h deleted file mode 100644 index e266395..0000000 --- a/arch/arm/include/asm/arch-tegra124/spl.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * (C) Copyright 2010-2013 - * NVIDIA Corporation <www.nvidia.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -#define BOOT_DEVICE_RAM 1 - -#endif /* _ASM_ARCH_SPL_H_ */ diff --git a/arch/arm/include/asm/arch-tegra20/spl.h b/arch/arm/include/asm/arch-tegra20/spl.h deleted file mode 100644 index 8953b00..0000000 --- a/arch/arm/include/asm/arch-tegra20/spl.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * (C) Copyright 2012 - * NVIDIA Corporation <www.nvidia.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -#define BOOT_DEVICE_RAM 1 - -#endif diff --git a/arch/arm/include/asm/arch-tegra30/spl.h b/arch/arm/include/asm/arch-tegra30/spl.h deleted file mode 100644 index 8953b00..0000000 --- a/arch/arm/include/asm/arch-tegra30/spl.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * (C) Copyright 2012 - * NVIDIA Corporation <www.nvidia.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#ifndef _ASM_ARCH_SPL_H_ -#define _ASM_ARCH_SPL_H_ - -#define BOOT_DEVICE_RAM 1 - -#endif diff --git a/arch/arm/include/asm/spl.h b/arch/arm/include/asm/spl.h index 90e5a9d..18a319d 100644 --- a/arch/arm/include/asm/spl.h +++ b/arch/arm/include/asm/spl.h @@ -7,9 +7,29 @@ #ifndef _ASM_SPL_H_ #define _ASM_SPL_H_
+#if defined(CONFIG_OMAP) || defined(CONFIG_SOCFPGA) || defined(CONFIG_ZYNQ) \ + || defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5) \ + || defined(CONFIG_EXYNOS4210) /* Platform-specific defines */ #include <asm/arch/spl.h>
+#else +enum { + BOOT_DEVICE_RAM, + BOOT_DEVICE_MMC1, + BOOT_DEVICE_MMC2, + BOOT_DEVICE_MMC2_2, + BOOT_DEVICE_NAND, + BOOT_DEVICE_ONENAND, + BOOT_DEVICE_NOR, + BOOT_DEVICE_UART, + BOOT_DEVICE_SPI, + BOOT_DEVICE_SATA, + BOOT_DEVICE_I2C, + BOOT_DEVICE_NONE +}; +#endif + /* Linker symbols. */ extern char __bss_start[], __bss_end[];
diff --git a/board/denx/m53evk/m53evk.c b/board/denx/m53evk/m53evk.c index 74f9501..5dd6cdd 100644 --- a/board/denx/m53evk/m53evk.c +++ b/board/denx/m53evk/m53evk.c @@ -14,7 +14,7 @@ #include <asm/arch/clock.h> #include <asm/arch/iomux-mx53.h> #include <asm/imx-common/mx5_video.h> -#include <asm/arch/spl.h> +#include <asm/spl.h> #include <asm/errno.h> #include <netdev.h> #include <i2c.h>

Hi Tim, Cc : Stefano, Tom
On Mon, 28 Apr 2014 13:17:30 -0700 Tim Harvey tharvey@gateworks.com wrote:
From: Masahiro Yamada yamada.m@jp.panasonic.com
arch/arm/include/asm/spl.h requires all SoCs to have arch/arm/include/asm/arch-*/spl.h.
But many of them just define BOOT_DEVICE_* macros.
Those macros are used in the "switch (boot_device) { ... }" statement in common/spl/spl.c.
So they should not be archtecture specific, but be described as a simpile enumeration.
This commit merges most of arch/arm/include/asm/arch-*/spl.h into arch/arm/include/asm/spl.h.
With a little more effort, arch-zynq/spl.h and arch-socfpga/spl.h will be merged, while I am not sure about OMAP and Exynos.
Signed-off-by: Masahiro Yamada yamada.m@jp.panasonic.com Cc: Tom Rini trini@ti.com Cc: Michal Simek michal.simek@xilinx.com Cc: Andreas Biesmann andreas.devel@googlemail.com Cc: Stephen Warren swarren@nvidia.com Cc: Tom Warren twarren@nvidia.com CC: Stefano Babic sbabic@denx.de CC: Minkyu Kang mk7.kang@samsung.com Cc: Dinh Nguyen dinguyen@altera.com Acked-by: Andreas Biesmann andreas.devel@googlemail.com Acked-by: Michal Simek monstr@monstr.eu Acked-by: Stefano Babic sbabic@denx.de Acked-by: Stephen Warren swarren@nvidia.com Acked-by: Tim Harvey tharvey@gateworks.com Tested-by: Bo Shen voice.shen@atmel.com [on sama5d3xek board for at91 part] Acked-by: Stephen Warren swarren@nvidia.com Signed-off-by: Tim Harvey tharvey@gateworks.com
I understand my patch is here because your series uses it as a prerequisite.
But, please make sure this patch should be reviewed and applied by Tom Rini because this patch is relevant to various SoCs.
Best Regards Masahiro Yamada

Hi Tim,
On 30/04/2014 07:39, Masahiro Yamada wrote:
Hi Tim, Cc : Stefano, Tom
On Mon, 28 Apr 2014 13:17:30 -0700 Tim Harvey tharvey@gateworks.com wrote:
From: Masahiro Yamada yamada.m@jp.panasonic.com
arch/arm/include/asm/spl.h requires all SoCs to have arch/arm/include/asm/arch-*/spl.h.
But many of them just define BOOT_DEVICE_* macros.
Those macros are used in the "switch (boot_device) { ... }" statement in common/spl/spl.c.
So they should not be archtecture specific, but be described as a simpile enumeration.
This commit merges most of arch/arm/include/asm/arch-*/spl.h into arch/arm/include/asm/spl.h.
With a little more effort, arch-zynq/spl.h and arch-socfpga/spl.h will be merged, while I am not sure about OMAP and Exynos.
Signed-off-by: Masahiro Yamada yamada.m@jp.panasonic.com Cc: Tom Rini trini@ti.com Cc: Michal Simek michal.simek@xilinx.com Cc: Andreas Biesmann andreas.devel@googlemail.com Cc: Stephen Warren swarren@nvidia.com Cc: Tom Warren twarren@nvidia.com CC: Stefano Babic sbabic@denx.de CC: Minkyu Kang mk7.kang@samsung.com Cc: Dinh Nguyen dinguyen@altera.com Acked-by: Andreas Biesmann andreas.devel@googlemail.com Acked-by: Michal Simek monstr@monstr.eu Acked-by: Stefano Babic sbabic@denx.de Acked-by: Stephen Warren swarren@nvidia.com Acked-by: Tim Harvey tharvey@gateworks.com Tested-by: Bo Shen voice.shen@atmel.com [on sama5d3xek board for at91 part] Acked-by: Stephen Warren swarren@nvidia.com Signed-off-by: Tim Harvey tharvey@gateworks.com
I understand my patch is here because your series uses it as a prerequisite.
But, please make sure this patch should be reviewed and applied by Tom Rini because this patch is relevant to various SoCs.
Indeed. Tim, it is enough you add in the cover letter for the next version that your patchset depends on Masahiro's patch, without including it in your series. I will check by merging if all dependencies will be satisfied.
Best regards, Stefano Babic

Add a common spl.c file to support boot device functions needed for SPL such as detecting the boot device.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- v2: - re-base on top of Masahiro Yamada's consolidation patch: http://patchwork.ozlabs.org/patch/341817/ - moved spl_boot_device() and get_boot_mode() into own common imx spl.c file - use mem-mapped structure for smbr reg access --- arch/arm/imx-common/Makefile | 1 + arch/arm/imx-common/spl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 arch/arm/imx-common/spl.c
diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile index b04dfbb..c97ea48 100644 --- a/arch/arm/imx-common/Makefile +++ b/arch/arm/imx-common/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o endif ifeq ($(SOC),$(filter $(SOC),mx6 mxs)) obj-y += misc.o +obj-$(CONFIG_SPL_BUILD) += spl.o endif ifeq ($(SOC),$(filter $(SOC),mx6)) obj-$(CONFIG_CMD_SATA) += sata.o diff --git a/arch/arm/imx-common/spl.c b/arch/arm/imx-common/spl.c new file mode 100644 index 0000000..5c1667c --- /dev/null +++ b/arch/arm/imx-common/spl.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Gateworks Corporation + * Author: Tim Harvey tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/spl.h> +#include <spl.h> + +#if defined(CONFIG_MX6) +/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +u32 spl_boot_device(void) +{ + struct src *psrc = (struct src *)SRC_BASE_ADDR; + unsigned reg = readl(&psrc->sbmr1); + + /* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */ + switch ((reg & 0x000000FF) >> 4) { + /* EIM: See 8.5.1, Table 8-9 */ + case 0x0: + /* BOOT_CFG1[3]: NOR/OneNAND Selection */ + if ((reg & 0x00000008) >> 3) + return BOOT_DEVICE_ONENAND; + else + return BOOT_DEVICE_NOR; + break; + /* SATA: See 8.5.4, Table 8-20 */ + case 0x2: + return BOOT_DEVICE_SATA; + /* Serial ROM: See 8.5.5.1, Table 8-22 */ + case 0x3: + /* BOOT_CFG4[2:0] */ + switch ((reg & 0x07000000) >> 24) { + case 0x0 ... 0x4: + return BOOT_DEVICE_SPI; + case 0x5 ... 0x7: + return BOOT_DEVICE_I2C; + } + break; + /* SD/eSD: 8.5.3, Table 8-15 */ + case 0x4: + case 0x5: + return BOOT_DEVICE_MMC1; + /* MMC/eMMC: 8.5.3 */ + case 0x6: + case 0x7: + return BOOT_DEVICE_MMC1; + /* NAND Flash: 8.5.2 */ + case 0x8 ... 0xf: + return BOOT_DEVICE_NAND; + } + return BOOT_DEVICE_NONE; +} +#endif + +#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 (spl_boot_device()) { + /* for MMC return either RAW or FAT mode */ + case BOOT_DEVICE_MMC1: + case BOOT_DEVICE_MMC2: +#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

Hi Tim,
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add a common spl.c file to support boot device functions needed for SPL such as detecting the boot device.
<snip>
diff --git a/arch/arm/imx-common/spl.c b/arch/arm/imx-common/spl.c new file mode 100644 index 0000000..5c1667c --- /dev/null +++ b/arch/arm/imx-common/spl.c @@ -0,0 +1,79 @@
<snip>
+u32 spl_boot_device(void) +{
- struct src *psrc = (struct src *)SRC_BASE_ADDR;
- unsigned reg = readl(&psrc->sbmr1);
- /* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
- switch ((reg & 0x000000FF) >> 4) {
<snip>
- case 0x3:
/* BOOT_CFG4[2:0] */
switch ((reg & 0x07000000) >> 24) {
This made me want a language lawyer, although I do see case ranges used in arch/blackfin/cpu/traps.c
case 0x0 ... 0x4:
return BOOT_DEVICE_SPI;
case 0x5 ... 0x7:
return BOOT_DEVICE_I2C;
}
Regards,
Eric

Hi Tim,
On 28/04/2014 22:17, Tim Harvey wrote:
Add a common spl.c file to support boot device functions needed for SPL such as detecting the boot device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- re-base on top of Masahiro Yamada's consolidation patch: http://patchwork.ozlabs.org/patch/341817/
- moved spl_boot_device() and get_boot_mode() into own common imx spl.c file
- use mem-mapped structure for smbr reg access
arch/arm/imx-common/Makefile | 1 + arch/arm/imx-common/spl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 arch/arm/imx-common/spl.c
diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile index b04dfbb..c97ea48 100644 --- a/arch/arm/imx-common/Makefile +++ b/arch/arm/imx-common/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o endif ifeq ($(SOC),$(filter $(SOC),mx6 mxs)) obj-y += misc.o +obj-$(CONFIG_SPL_BUILD) += spl.o endif ifeq ($(SOC),$(filter $(SOC),mx6)) obj-$(CONFIG_CMD_SATA) += sata.o diff --git a/arch/arm/imx-common/spl.c b/arch/arm/imx-common/spl.c new file mode 100644 index 0000000..5c1667c --- /dev/null +++ b/arch/arm/imx-common/spl.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
Just a little remark. Do you have written the function on your own or have you ported it from Freescale's 2009.08 ? Apart names, it looks similar.
If this is the case, you should also add Freescale's Copyright to the header.
+#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/spl.h> +#include <spl.h>
+#if defined(CONFIG_MX6) +/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +u32 spl_boot_device(void) +{
- struct src *psrc = (struct src *)SRC_BASE_ADDR;
- unsigned reg = readl(&psrc->sbmr1);
- /* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
- switch ((reg & 0x000000FF) >> 4) {
/* EIM: See 8.5.1, Table 8-9 */
- case 0x0:
/* BOOT_CFG1[3]: NOR/OneNAND Selection */
if ((reg & 0x00000008) >> 3)
return BOOT_DEVICE_ONENAND;
else
return BOOT_DEVICE_NOR;
break;
- /* SATA: See 8.5.4, Table 8-20 */
- case 0x2:
return BOOT_DEVICE_SATA;
- /* Serial ROM: See 8.5.5.1, Table 8-22 */
- case 0x3:
/* BOOT_CFG4[2:0] */
switch ((reg & 0x07000000) >> 24) {
case 0x0 ... 0x4:
return BOOT_DEVICE_SPI;
case 0x5 ... 0x7:
return BOOT_DEVICE_I2C;
}
break;
- /* SD/eSD: 8.5.3, Table 8-15 */
- case 0x4:
- case 0x5:
return BOOT_DEVICE_MMC1;
- /* MMC/eMMC: 8.5.3 */
- case 0x6:
- case 0x7:
return BOOT_DEVICE_MMC1;
- /* NAND Flash: 8.5.2 */
- case 0x8 ... 0xf:
return BOOT_DEVICE_NAND;
- }
- return BOOT_DEVICE_NONE;
+} +#endif
+#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 (spl_boot_device()) {
- /* for MMC return either RAW or FAT mode */
- case BOOT_DEVICE_MMC1:
- case BOOT_DEVICE_MMC2:
+#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
Best regards, Stefano Babic

+cc Edward Lin
On Mon, May 5, 2014 at 2:14 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
On 28/04/2014 22:17, Tim Harvey wrote:
Add a common spl.c file to support boot device functions needed for SPL such as detecting the boot device.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- re-base on top of Masahiro Yamada's consolidation patch: http://patchwork.ozlabs.org/patch/341817/
- moved spl_boot_device() and get_boot_mode() into own common imx spl.c file
- use mem-mapped structure for smbr reg access
arch/arm/imx-common/Makefile | 1 + arch/arm/imx-common/spl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 arch/arm/imx-common/spl.c
diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile index b04dfbb..c97ea48 100644 --- a/arch/arm/imx-common/Makefile +++ b/arch/arm/imx-common/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SYS_I2C_MXC) += i2c-mxv7.o endif ifeq ($(SOC),$(filter $(SOC),mx6 mxs)) obj-y += misc.o +obj-$(CONFIG_SPL_BUILD) += spl.o endif ifeq ($(SOC),$(filter $(SOC),mx6)) obj-$(CONFIG_CMD_SATA) += sata.o diff --git a/arch/arm/imx-common/spl.c b/arch/arm/imx-common/spl.c new file mode 100644 index 0000000..5c1667c --- /dev/null +++ b/arch/arm/imx-common/spl.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
Just a little remark. Do you have written the function on your own or have you ported it from Freescale's 2009.08 ? Apart names, it looks similar.
If this is the case, you should also add Freescale's Copyright to the header.
Hi Stefano,
I've never looked at Freescales 2009.08 code myself (I have an aversion to vendor specific forks of u-boot almost 5 years old heh), but its likely bits of the function came from there originally but my inspiration likely came from Edward Lin's patch a while back. A switch/case seems the logical approach given the bitfield from the IMX6 reference manual with several don't-cares spread around and I felt that was much easier to read than trying to convert it all the shifts and masks.
I can add additional copyright's if anyone feels its necessary - I've added Edward to the cc to see if he feels its necessary.
Tim
+#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/spl.h> +#include <spl.h>
+#if defined(CONFIG_MX6) +/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +u32 spl_boot_device(void) +{
struct src *psrc = (struct src *)SRC_BASE_ADDR;
unsigned reg = readl(&psrc->sbmr1);
/* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
switch ((reg & 0x000000FF) >> 4) {
/* EIM: See 8.5.1, Table 8-9 */
case 0x0:
/* BOOT_CFG1[3]: NOR/OneNAND Selection */
if ((reg & 0x00000008) >> 3)
return BOOT_DEVICE_ONENAND;
else
return BOOT_DEVICE_NOR;
break;
/* SATA: See 8.5.4, Table 8-20 */
case 0x2:
return BOOT_DEVICE_SATA;
/* Serial ROM: See 8.5.5.1, Table 8-22 */
case 0x3:
/* BOOT_CFG4[2:0] */
switch ((reg & 0x07000000) >> 24) {
case 0x0 ... 0x4:
return BOOT_DEVICE_SPI;
case 0x5 ... 0x7:
return BOOT_DEVICE_I2C;
}
break;
/* SD/eSD: 8.5.3, Table 8-15 */
case 0x4:
case 0x5:
return BOOT_DEVICE_MMC1;
/* MMC/eMMC: 8.5.3 */
case 0x6:
case 0x7:
return BOOT_DEVICE_MMC1;
/* NAND Flash: 8.5.2 */
case 0x8 ... 0xf:
return BOOT_DEVICE_NAND;
}
return BOOT_DEVICE_NONE;
+} +#endif
+#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 (spl_boot_device()) {
/* for MMC return either RAW or FAT mode */
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
+#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
Best regards, Stefano Babic
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de =====================================================================

Hi Tim,
On 05/05/2014 17:46, Tim Harvey wrote:
Just a little remark. Do you have written the function on your own or have you ported it from Freescale's 2009.08 ? Apart names, it looks similar.
If this is the case, you should also add Freescale's Copyright to the header.
Hi Stefano,
I've never looked at Freescales 2009.08 code myself (I have an aversion to vendor specific forks of u-boot almost 5 years old heh), but its likely bits of the function came from there originally but my inspiration likely came from Edward Lin's patch a while back. A switch/case seems the logical approach given the bitfield from the IMX6 reference manual with several don't-cares spread around and I felt that was much easier to read than trying to convert it all the shifts and masks.
This is ok - I want only to be sure that Copyright is maintained if code is taken from somewhere else.
I can add additional copyright's if anyone feels its necessary - I've added Edward to the cc to see if he feels its necessary.
Ok - if nobody complains, you can leave it as it is now.
Best regards, Stefano

On Mon, 5 May 2014 08:46:24 -0700 Tim Harvey tharvey@gateworks.com wrote:
+cc Edward Lin
On Mon, May 5, 2014 at 2:14 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
...
--- /dev/null +++ b/arch/arm/imx-common/spl.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- Author: Tim Harvey tharvey@gateworks.com
- SPDX-License-Identifier: GPL-2.0+
- */
Just a little remark. Do you have written the function on your own or have you ported it from Freescale's 2009.08 ? Apart names, it looks similar.
If this is the case, you should also add Freescale's Copyright to the header.
Hi Stefano,
I've never looked at Freescales 2009.08 code myself (I have an aversion to vendor specific forks of u-boot almost 5 years old heh), but its likely bits of the function came from there originally but my inspiration likely came from Edward Lin's patch a while back. A switch/case seems the logical approach given the bitfield from the IMX6 reference manual with several don't-cares spread around and I felt that was much easier to read than trying to convert it all the shifts and masks.
I can add additional copyright's if anyone feels its necessary - I've added Edward to the cc to see if he feels its necessary.
Tim
+#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/spl.h> +#include <spl.h>
+#if defined(CONFIG_MX6) +/* determine boot device from SRC_SBMR1 register (BOOT_CFG[4:1]) */ +u32 spl_boot_device(void) +{
struct src *psrc = (struct src *)SRC_BASE_ADDR;
unsigned reg = readl(&psrc->sbmr1);
/* BOOT_CFG1[7:4] - see IMX6DQRM Table 8-8 */
switch ((reg & 0x000000FF) >> 4) {
/* EIM: See 8.5.1, Table 8-9 */
case 0x0:
/* BOOT_CFG1[3]: NOR/OneNAND Selection */
if ((reg & 0x00000008) >> 3)
return BOOT_DEVICE_ONENAND;
else
return BOOT_DEVICE_NOR;
break;
/* SATA: See 8.5.4, Table 8-20 */
case 0x2:
return BOOT_DEVICE_SATA;
/* Serial ROM: See 8.5.5.1, Table 8-22 */
case 0x3:
/* BOOT_CFG4[2:0] */
switch ((reg & 0x07000000) >> 24) {
case 0x0 ... 0x4:
return BOOT_DEVICE_SPI;
case 0x5 ... 0x7:
return BOOT_DEVICE_I2C;
}
break;
/* SD/eSD: 8.5.3, Table 8-15 */
case 0x4:
case 0x5:
return BOOT_DEVICE_MMC1;
/* MMC/eMMC: 8.5.3 */
case 0x6:
case 0x7:
return BOOT_DEVICE_MMC1;
/* NAND Flash: 8.5.2 */
case 0x8 ... 0xf:
return BOOT_DEVICE_NAND;
}
return BOOT_DEVICE_NONE;
+} +#endif
+#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 (spl_boot_device()) {
/* for MMC return either RAW or FAT mode */
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
+#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
Tim, Stefano,
that piece of code indeed originates from Freescale's 2009.08 u-boot. (Edward has changed jobs, so the CC:d address is of no use.)
regards,
//Tapani
ps: Tim, thanks for getting the SPL framework mainlined!

Hi Tim,
On 06/05/2014 08:36, Tapani Utriainen wrote:
Tim, Stefano,
that piece of code indeed originates from Freescale's 2009.08 u-boot. (Edward has changed jobs, so the CC:d address is of no use.)
I supposed this. Tim, please add Freescale's Copyright, too.
Thanks, Stefano Babic

On Tue, May 6, 2014 at 12:55 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
On 06/05/2014 08:36, Tapani Utriainen wrote:
Tim, Stefano,
that piece of code indeed originates from Freescale's 2009.08 u-boot. (Edward has changed jobs, so the CC:d address is of no use.)
I supposed this. Tim, please add Freescale's Copyright, too.
Thanks, Stefano Babic
ok - will do. Thanks for the heads-up Tapani.
Tim

Add comment block for the imx_ddr_size function and remove the extra unused fields from struct esd_mmdc_regs which are also not common between IMX53 and IMX6. There are no functional changes here.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- arch/arm/imx-common/cpu.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/arm/imx-common/cpu.c b/arch/arm/imx-common/cpu.c index a77c4de..392b8d4 100644 --- a/arch/arm/imx-common/cpu.c +++ b/arch/arm/imx-common/cpu.c @@ -58,6 +58,7 @@ char *get_reset_cause(void) static const unsigned char col_lookup[] = {9, 10, 11, 8, 12, 9, 9, 9}; static const unsigned char bank_lookup[] = {3, 2};
+/* these MMDC registers are common to the IMX53 and IMX6 */ struct esd_mmdc_regs { uint32_t ctl; uint32_t pdc; @@ -66,15 +67,6 @@ struct esd_mmdc_regs { uint32_t cfg1; uint32_t cfg2; uint32_t misc; - uint32_t scr; - uint32_t ref; - uint32_t rsvd1; - uint32_t rsvd2; - uint32_t rwd; - uint32_t or; - uint32_t mrr; - uint32_t cfg3lp; - uint32_t mr4; };
#define ESD_MMDC_CTL_GET_ROW(mdctl) ((ctl >> 24) & 7) @@ -83,6 +75,12 @@ struct esd_mmdc_regs { #define ESD_MMDC_CTL_GET_CS1(mdctl) ((ctl >> 30) & 1) #define ESD_MMDC_MISC_GET_BANK(mdmisc) ((misc >> 5) & 1)
+/** + * imx_ddr_size - return size in bytes of DRAM according MMDC config + * The MMDC MDCTL register holds the number of bits for row, col, and data + * width and the MMDC MDMISC register holds the number of banks. Combine + * all these bits to determine the meme size the MMDC has been configured for + */ unsigned imx_ddr_size(void) { struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE;

Hi Tim,
On 28/04/2014 22:17, Tim Harvey wrote:
Add comment block for the imx_ddr_size function and remove the extra unused fields from struct esd_mmdc_regs which are also not common between IMX53 and IMX6. There are no functional changes here.
Signed-off-by: Tim Harvey tharvey@gateworks.com
arch/arm/imx-common/cpu.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/arm/imx-common/cpu.c b/arch/arm/imx-common/cpu.c index a77c4de..392b8d4 100644 --- a/arch/arm/imx-common/cpu.c +++ b/arch/arm/imx-common/cpu.c @@ -58,6 +58,7 @@ char *get_reset_cause(void) static const unsigned char col_lookup[] = {9, 10, 11, 8, 12, 9, 9, 9}; static const unsigned char bank_lookup[] = {3, 2};
+/* these MMDC registers are common to the IMX53 and IMX6 */ struct esd_mmdc_regs { uint32_t ctl; uint32_t pdc; @@ -66,15 +67,6 @@ struct esd_mmdc_regs { uint32_t cfg1; uint32_t cfg2; uint32_t misc;
- uint32_t scr;
- uint32_t ref;
- uint32_t rsvd1;
- uint32_t rsvd2;
- uint32_t rwd;
- uint32_t or;
- uint32_t mrr;
- uint32_t cfg3lp;
- uint32_t mr4;
};
#define ESD_MMDC_CTL_GET_ROW(mdctl) ((ctl >> 24) & 7) @@ -83,6 +75,12 @@ struct esd_mmdc_regs { #define ESD_MMDC_CTL_GET_CS1(mdctl) ((ctl >> 30) & 1) #define ESD_MMDC_MISC_GET_BANK(mdmisc) ((misc >> 5) & 1)
+/**
Just a *very* minor point: why do you introduce doxygen-like comment ? As U-Boot does not support it, this is uncommon and not useful.
- imx_ddr_size - return size in bytes of DRAM according MMDC config
- The MMDC MDCTL register holds the number of bits for row, col, and data
- width and the MMDC MDMISC register holds the number of banks. Combine
- all these bits to determine the meme size the MMDC has been configured for
- */
unsigned imx_ddr_size(void) { struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE;
Apart of that:
Acked-by: Stefano Babic sbabic@denx.de
Best regards, Stefano Babic

Add memory-mapped structures for MMDC iomux and configuration. Note that while the MMDC configuration registers are common between the IMX6DQ (IMX6DUAL/IMX6QUAD) and IMX6SDL (IMX6SOLO/IMX6DUALLITE) types the iomux registers differ. This requires two sets of structures.
Add structures to describe DDR3 device information, system information (memory layout, etc), and MMDC calibration regitsers that can be used to configure the MMDC dynamically.
We define these structures for SPL builds instead of including mx6q-ddr.h and mx6dl-ddr.h which use the same namespace and are only useful for imximage cfg files.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- v2: - split out from original mmdc configuration patch - only define for SPL build - do not include mx6q-ddr.h and mx6dl-ddr.h for SPL build - these use the same namespace and are only useful for imximage cfg files --- arch/arm/include/asm/arch-mx6/mx6-ddr.h | 231 ++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 43d377a..d544d2e 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -6,6 +6,7 @@ #ifndef __ASM_ARCH_MX6_DDR_H__ #define __ASM_ARCH_MX6_DDR_H__
+#ifndef CONFIG_SPL_BUILD #ifdef CONFIG_MX6Q #include "mx6q-ddr.h" #else @@ -15,6 +16,236 @@ #error "Please select cpu" #endif /* CONFIG_MX6DL or CONFIG_MX6S */ #endif /* CONFIG_MX6Q */ +#else + +/* MMDC P0/P1 Registers */ +struct mmdc_p_regs { + u32 mdctl; + u32 mdpdc; + u32 mdotc; + u32 mdcfg0; + u32 mdcfg1; + u32 mdcfg2; + u32 mdmisc; + u32 mdscr; + u32 mdref; + u32 res1[2]; + u32 mdrwd; + u32 mdor; + u32 res2[3]; + u32 mdasp; + u32 res3[240]; + u32 mapsr; + u32 res4[254]; + u32 mpzqhwctrl; + u32 res5[2]; + u32 mpwldectrl0; + u32 mpwldectrl1; + u32 res6; + u32 mpodtctrl; + u32 mprddqby0dl; + u32 mprddqby1dl; + u32 mprddqby2dl; + u32 mprddqby3dl; + u32 res7[4]; + u32 mpdgctrl0; + u32 mpdgctrl1; + u32 res8; + u32 mprddlctl; + u32 res9; + u32 mpwrdlctl; + u32 res10[25]; + u32 mpmur0; +}; + +/* + * MMDC iomux registers (pinctl/padctl) - (different for IMX6DQ vs IMX6SDL) + */ +#define MX6DQ_IOM_DDR_BASE 0x020e0500 +struct mx6dq_iomux_ddr_regs { + u32 res1[3]; + u32 dram_sdqs5; + u32 dram_dqm5; + u32 dram_dqm4; + u32 dram_sdqs4; + u32 dram_sdqs3; + u32 dram_dqm3; + u32 dram_sdqs2; + u32 dram_dqm2; + u32 res2[16]; + u32 dram_cas; + u32 res3[2]; + u32 dram_ras; + u32 dram_reset; + u32 res4[2]; + u32 dram_sdclk_0; + u32 dram_sdba2; + u32 dram_sdcke0; + u32 dram_sdclk_1; + u32 dram_sdcke1; + u32 dram_sdodt0; + u32 dram_sdodt1; + u32 res5; + u32 dram_sdqs0; + u32 dram_dqm0; + u32 dram_sdqs1; + u32 dram_dqm1; + u32 dram_sdqs6; + u32 dram_dqm6; + u32 dram_sdqs7; + u32 dram_dqm7; +}; + +#define MX6DQ_IOM_GRP_BASE 0x020e0700 +struct mx6dq_iomux_grp_regs { + u32 res1[18]; + u32 grp_b7ds; + u32 grp_addds; + u32 grp_ddrmode_ctl; + u32 res2; + u32 grp_ddrpke; + u32 res3[6]; + u32 grp_ddrmode; + u32 res4[3]; + u32 grp_b0ds; + u32 grp_b1ds; + u32 grp_ctlds; + u32 res5; + u32 grp_b2ds; + u32 grp_ddr_type; + u32 grp_b3ds; + u32 grp_b4ds; + u32 grp_b5ds; + u32 grp_b6ds; +}; + +#define MX6SDL_IOM_DDR_BASE 0x020e0400 +struct mx6sdl_iomux_ddr_regs { + u32 res1[25]; + u32 dram_cas; + u32 res2[2]; + u32 dram_dqm0; + u32 dram_dqm1; + u32 dram_dqm2; + u32 dram_dqm3; + u32 dram_dqm4; + u32 dram_dqm5; + u32 dram_dqm6; + u32 dram_dqm7; + u32 dram_ras; + u32 dram_reset; + u32 res3[2]; + u32 dram_sdba2; + u32 dram_sdcke0; + u32 dram_sdcke1; + u32 dram_sdclk_0; + u32 dram_sdclk_1; + u32 dram_sdodt0; + u32 dram_sdodt1; + u32 dram_sdqs0; + u32 dram_sdqs1; + u32 dram_sdqs2; + u32 dram_sdqs3; + u32 dram_sdqs4; + u32 dram_sdqs5; + u32 dram_sdqs6; + u32 dram_sdqs7; +}; + +#define MX6SDL_IOM_GRP_BASE 0x020e0700 +struct mx6sdl_iomux_grp_regs { + u32 res1[18]; + u32 grp_b7ds; + u32 grp_addds; + u32 grp_ddrmode_ctl; + u32 grp_ddrpke; + u32 res2[2]; + u32 grp_ddrmode; + u32 grp_b0ds; + u32 res3; + u32 grp_ctlds; + u32 grp_b1ds; + u32 grp_ddr_type; + u32 grp_b2ds; + u32 grp_b3ds; + u32 grp_b4ds; + u32 grp_b5ds; + u32 res4; + u32 grp_b6ds; +}; + +/* 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, layout, and term 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 p0_mpwldectrl0; + u32 p0_mpwldectrl1; + u32 p1_mpwldectrl0; + u32 p1_mpwldectrl1; + /* read DQS gating */ + u32 p0_mpdgctrl0; + u32 p0_mpdgctrl1; + u32 p1_mpdgctrl0; + u32 p1_mpdgctrl1; + /* read delay */ + u32 p0_mprddlctl; + u32 p1_mprddlctl; + /* write delay */ + u32 p0_mpwrdlctl; + u32 p1_mpwrdlctl; +}; + +/* configure iomux (pinctl/padctl) */ +void mx6dq_dram_iocfg(unsigned width, + const struct mx6dq_iomux_ddr_regs *, + const struct mx6dq_iomux_grp_regs *); +void mx6sdl_dram_iocfg(unsigned width, + const struct mx6sdl_iomux_ddr_regs *, + const struct mx6sdl_iomux_grp_regs *); + +/* configure mx6 mmdc registers */ +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *, + const struct mx6_mmdc_calibration *, + const struct mx6_ddr3_cfg *); + +#endif /* CONFIG_SPL_BUILD */
#define MX6_MMDC_P0_MDCTL 0x021b0000 #define MX6_MMDC_P0_MDPDC 0x021b0004

Hi Tim,
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add memory-mapped structures for MMDC iomux and configuration. Note that while the MMDC configuration registers are common between the IMX6DQ (IMX6DUAL/IMX6QUAD) and IMX6SDL (IMX6SOLO/IMX6DUALLITE) types the iomux registers differ. This requires two sets of structures.
Add structures to describe DDR3 device information, system information (memory layout, etc), and MMDC calibration regitsers that can be used to configure the MMDC dynamically.
We define these structures for SPL builds instead of including mx6q-ddr.h and mx6dl-ddr.h which use the same namespace and are only useful for imximage cfg files.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- split out from original mmdc configuration patch
- only define for SPL build
- do not include mx6q-ddr.h and mx6dl-ddr.h for SPL build - these use the same namespace and are only useful for imximage cfg files
arch/arm/include/asm/arch-mx6/mx6-ddr.h | 231 ++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 43d377a..d544d2e 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -6,6 +6,7 @@ #ifndef __ASM_ARCH_MX6_DDR_H__ #define __ASM_ARCH_MX6_DDR_H__
+#ifndef CONFIG_SPL_BUILD #ifdef CONFIG_MX6Q #include "mx6q-ddr.h" #else @@ -15,6 +16,236 @@ #error "Please select cpu" #endif /* CONFIG_MX6DL or CONFIG_MX6S */ #endif /* CONFIG_MX6Q */ +#else
This part of the patch matches the commit message for patch 7.
+/* MMDC P0/P1 Registers */ +struct mmdc_p_regs {
- u32 mdctl;
- u32 mdpdc;
- u32 mdotc;
- u32 mdcfg0;
- u32 mdcfg1;
- u32 mdcfg2;
- u32 mdmisc;
- u32 mdscr;
...
The following bits should probably be moved into patch 8 though:
+/* 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, layout, and term 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 p0_mpwldectrl0;
- u32 p0_mpwldectrl1;
- u32 p1_mpwldectrl0;
- u32 p1_mpwldectrl1;
- /* read DQS gating */
- u32 p0_mpdgctrl0;
- u32 p0_mpdgctrl1;
- u32 p1_mpdgctrl0;
- u32 p1_mpdgctrl1;
- /* read delay */
- u32 p0_mprddlctl;
- u32 p1_mprddlctl;
- /* write delay */
- u32 p0_mpwrdlctl;
- u32 p1_mpwrdlctl;
+};
Nicely done!
This partitioning of chip-level, design-level, and calibration data makes perfect sense.
+/* configure iomux (pinctl/padctl) */ +void mx6dq_dram_iocfg(unsigned width,
const struct mx6dq_iomux_ddr_regs *,
const struct mx6dq_iomux_grp_regs *);
+void mx6sdl_dram_iocfg(unsigned width,
const struct mx6sdl_iomux_ddr_regs *,
const struct mx6sdl_iomux_grp_regs *);
+/* configure mx6 mmdc registers */ +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *,
const struct mx6_mmdc_calibration *,
const struct mx6_ddr3_cfg *);
+#endif /* CONFIG_SPL_BUILD */
#define MX6_MMDC_P0_MDCTL 0x021b0000 #define MX6_MMDC_P0_MDPDC 0x021b0004
Regards,
Eric

Hi Tim,
On 28/04/2014 22:17, Tim Harvey wrote:
Add memory-mapped structures for MMDC iomux and configuration. Note that while the MMDC configuration registers are common between the IMX6DQ (IMX6DUAL/IMX6QUAD) and IMX6SDL (IMX6SOLO/IMX6DUALLITE) types the iomux registers differ. This requires two sets of structures.
Add structures to describe DDR3 device information, system information (memory layout, etc), and MMDC calibration regitsers that can be used to configure the MMDC dynamically.
We define these structures for SPL builds instead of including mx6q-ddr.h and mx6dl-ddr.h which use the same namespace and are only useful for imximage cfg files.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- split out from original mmdc configuration patch
- only define for SPL build
- do not include mx6q-ddr.h and mx6dl-ddr.h for SPL build - these use the same namespace and are only useful for imximage cfg files
arch/arm/include/asm/arch-mx6/mx6-ddr.h | 231 ++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 43d377a..d544d2e 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -6,6 +6,7 @@ #ifndef __ASM_ARCH_MX6_DDR_H__ #define __ASM_ARCH_MX6_DDR_H__
+#ifndef CONFIG_SPL_BUILD #ifdef CONFIG_MX6Q #include "mx6q-ddr.h" #else @@ -15,6 +16,236 @@ #error "Please select cpu" #endif /* CONFIG_MX6DL or CONFIG_MX6S */ #endif /* CONFIG_MX6Q */ +#else
+/* MMDC P0/P1 Registers */ +struct mmdc_p_regs {
- u32 mdctl;
- u32 mdpdc;
- u32 mdotc;
- u32 mdcfg0;
- u32 mdcfg1;
- u32 mdcfg2;
- u32 mdmisc;
- u32 mdscr;
- u32 mdref;
- u32 res1[2];
- u32 mdrwd;
- u32 mdor;
- u32 res2[3];
- u32 mdasp;
- u32 res3[240];
- u32 mapsr;
- u32 res4[254];
- u32 mpzqhwctrl;
- u32 res5[2];
- u32 mpwldectrl0;
- u32 mpwldectrl1;
- u32 res6;
- u32 mpodtctrl;
- u32 mprddqby0dl;
- u32 mprddqby1dl;
- u32 mprddqby2dl;
- u32 mprddqby3dl;
- u32 res7[4];
- u32 mpdgctrl0;
- u32 mpdgctrl1;
- u32 res8;
- u32 mprddlctl;
- u32 res9;
- u32 mpwrdlctl;
- u32 res10[25];
- u32 mpmur0;
+};
+/*
- MMDC iomux registers (pinctl/padctl) - (different for IMX6DQ vs IMX6SDL)
- */
+#define MX6DQ_IOM_DDR_BASE 0x020e0500
It is only a question - having the value here let us know where the registers are located. Anyway, registers' offsets are stored in the imx-regs.h file of the SOC. Which is the reason to set them here ?
+struct mx6dq_iomux_ddr_regs {
- u32 res1[3];
- u32 dram_sdqs5;
- u32 dram_dqm5;
- u32 dram_dqm4;
- u32 dram_sdqs4;
- u32 dram_sdqs3;
- u32 dram_dqm3;
- u32 dram_sdqs2;
- u32 dram_dqm2;
- u32 res2[16];
- u32 dram_cas;
- u32 res3[2];
- u32 dram_ras;
- u32 dram_reset;
- u32 res4[2];
- u32 dram_sdclk_0;
- u32 dram_sdba2;
- u32 dram_sdcke0;
- u32 dram_sdclk_1;
- u32 dram_sdcke1;
- u32 dram_sdodt0;
- u32 dram_sdodt1;
- u32 res5;
- u32 dram_sdqs0;
- u32 dram_dqm0;
- u32 dram_sdqs1;
- u32 dram_dqm1;
- u32 dram_sdqs6;
- u32 dram_dqm6;
- u32 dram_sdqs7;
- u32 dram_dqm7;
+};
+#define MX6DQ_IOM_GRP_BASE 0x020e0700 +struct mx6dq_iomux_grp_regs {
- u32 res1[18];
- u32 grp_b7ds;
- u32 grp_addds;
- u32 grp_ddrmode_ctl;
- u32 res2;
- u32 grp_ddrpke;
- u32 res3[6];
- u32 grp_ddrmode;
- u32 res4[3];
- u32 grp_b0ds;
- u32 grp_b1ds;
- u32 grp_ctlds;
- u32 res5;
- u32 grp_b2ds;
- u32 grp_ddr_type;
- u32 grp_b3ds;
- u32 grp_b4ds;
- u32 grp_b5ds;
- u32 grp_b6ds;
+};
+#define MX6SDL_IOM_DDR_BASE 0x020e0400 +struct mx6sdl_iomux_ddr_regs {
- u32 res1[25];
- u32 dram_cas;
- u32 res2[2];
- u32 dram_dqm0;
- u32 dram_dqm1;
- u32 dram_dqm2;
- u32 dram_dqm3;
- u32 dram_dqm4;
- u32 dram_dqm5;
- u32 dram_dqm6;
- u32 dram_dqm7;
- u32 dram_ras;
- u32 dram_reset;
- u32 res3[2];
- u32 dram_sdba2;
- u32 dram_sdcke0;
- u32 dram_sdcke1;
- u32 dram_sdclk_0;
- u32 dram_sdclk_1;
- u32 dram_sdodt0;
- u32 dram_sdodt1;
- u32 dram_sdqs0;
- u32 dram_sdqs1;
- u32 dram_sdqs2;
- u32 dram_sdqs3;
- u32 dram_sdqs4;
- u32 dram_sdqs5;
- u32 dram_sdqs6;
- u32 dram_sdqs7;
+};
+#define MX6SDL_IOM_GRP_BASE 0x020e0700 +struct mx6sdl_iomux_grp_regs {
- u32 res1[18];
- u32 grp_b7ds;
- u32 grp_addds;
- u32 grp_ddrmode_ctl;
- u32 grp_ddrpke;
- u32 res2[2];
- u32 grp_ddrmode;
- u32 grp_b0ds;
- u32 res3;
- u32 grp_ctlds;
- u32 grp_b1ds;
- u32 grp_ddr_type;
- u32 grp_b2ds;
- u32 grp_b3ds;
- u32 grp_b4ds;
- u32 grp_b5ds;
- u32 res4;
- u32 grp_b6ds;
+};
+/* 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, layout, and term 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 p0_mpwldectrl0;
- u32 p0_mpwldectrl1;
- u32 p1_mpwldectrl0;
- u32 p1_mpwldectrl1;
- /* read DQS gating */
- u32 p0_mpdgctrl0;
- u32 p0_mpdgctrl1;
- u32 p1_mpdgctrl0;
- u32 p1_mpdgctrl1;
- /* read delay */
- u32 p0_mprddlctl;
- u32 p1_mprddlctl;
- /* write delay */
- u32 p0_mpwrdlctl;
- u32 p1_mpwrdlctl;
+};
I agree on theses structures. It is then simpler for a board maintainer to understand what is required to add SPL support for the own board.
+/* configure iomux (pinctl/padctl) */ +void mx6dq_dram_iocfg(unsigned width,
const struct mx6dq_iomux_ddr_regs *,
const struct mx6dq_iomux_grp_regs *);
+void mx6sdl_dram_iocfg(unsigned width,
const struct mx6sdl_iomux_ddr_regs *,
const struct mx6sdl_iomux_grp_regs *);
+/* configure mx6 mmdc registers */ +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *,
const struct mx6_mmdc_calibration *,
const struct mx6_ddr3_cfg *);
+#endif /* CONFIG_SPL_BUILD */
#define MX6_MMDC_P0_MDCTL 0x021b0000 #define MX6_MMDC_P0_MDPDC 0x021b0004
Best regards, Stefano Babic

On Mon, May 5, 2014 at 3:34 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
On 28/04/2014 22:17, Tim Harvey wrote:
Add memory-mapped structures for MMDC iomux and configuration. Note that while the MMDC configuration registers are common between the IMX6DQ (IMX6DUAL/IMX6QUAD) and IMX6SDL (IMX6SOLO/IMX6DUALLITE) types the iomux registers differ. This requires two sets of structures.
Add structures to describe DDR3 device information, system information (memory layout, etc), and MMDC calibration regitsers that can be used to configure the MMDC dynamically.
We define these structures for SPL builds instead of including mx6q-ddr.h and mx6dl-ddr.h which use the same namespace and are only useful for imximage cfg files.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- split out from original mmdc configuration patch
- only define for SPL build
- do not include mx6q-ddr.h and mx6dl-ddr.h for SPL build - these use the same namespace and are only useful for imximage cfg files
arch/arm/include/asm/arch-mx6/mx6-ddr.h | 231 ++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6-ddr.h b/arch/arm/include/asm/arch-mx6/mx6-ddr.h index 43d377a..d544d2e 100644 --- a/arch/arm/include/asm/arch-mx6/mx6-ddr.h +++ b/arch/arm/include/asm/arch-mx6/mx6-ddr.h @@ -6,6 +6,7 @@ #ifndef __ASM_ARCH_MX6_DDR_H__ #define __ASM_ARCH_MX6_DDR_H__
+#ifndef CONFIG_SPL_BUILD #ifdef CONFIG_MX6Q #include "mx6q-ddr.h" #else @@ -15,6 +16,236 @@ #error "Please select cpu" #endif /* CONFIG_MX6DL or CONFIG_MX6S */ #endif /* CONFIG_MX6Q */ +#else
+/* MMDC P0/P1 Registers */ +struct mmdc_p_regs {
u32 mdctl;
u32 mdpdc;
u32 mdotc;
u32 mdcfg0;
u32 mdcfg1;
u32 mdcfg2;
u32 mdmisc;
u32 mdscr;
u32 mdref;
u32 res1[2];
u32 mdrwd;
u32 mdor;
u32 res2[3];
u32 mdasp;
u32 res3[240];
u32 mapsr;
u32 res4[254];
u32 mpzqhwctrl;
u32 res5[2];
u32 mpwldectrl0;
u32 mpwldectrl1;
u32 res6;
u32 mpodtctrl;
u32 mprddqby0dl;
u32 mprddqby1dl;
u32 mprddqby2dl;
u32 mprddqby3dl;
u32 res7[4];
u32 mpdgctrl0;
u32 mpdgctrl1;
u32 res8;
u32 mprddlctl;
u32 res9;
u32 mpwrdlctl;
u32 res10[25];
u32 mpmur0;
+};
+/*
- MMDC iomux registers (pinctl/padctl) - (different for IMX6DQ vs IMX6SDL)
- */
+#define MX6DQ_IOM_DDR_BASE 0x020e0500
It is only a question - having the value here let us know where the registers are located. Anyway, registers' offsets are stored in the imx-regs.h file of the SOC. Which is the reason to set them here ?
I felt they belonged with the ddr structures themselves. I can move them but then will someone claim that the ddr structures should also be moved?
Tim

Add functions for configuring MMDC iomux and configuration based on board-specific configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- v2: - split out mmdc and iomux structs into separate patch --- arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 469 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 470 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..1536418 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2014 Gateworks Corporation + * 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> + +/* Configure MX6DQ mmdc iomux */ +void mx6dq_dram_iocfg(unsigned width, + const struct mx6dq_iomux_ddr_regs *ddr, + const struct mx6dq_iomux_grp_regs *grp) +{ + volatile struct mx6dq_iomux_ddr_regs *mx6_ddr_iomux; + volatile struct mx6dq_iomux_grp_regs *mx6_grp_iomux; + + mx6_ddr_iomux = (struct mx6dq_iomux_ddr_regs *)MX6DQ_IOM_DDR_BASE; + mx6_grp_iomux = (struct mx6dq_iomux_grp_regs *)MX6DQ_IOM_GRP_BASE; + + /* DDR IO Type */ + mx6_grp_iomux->grp_ddr_type = grp->grp_ddr_type; + mx6_grp_iomux->grp_ddrpke = grp->grp_ddrpke; + + /* Clock */ + mx6_ddr_iomux->dram_sdclk_0 = ddr->dram_sdclk_0; + mx6_ddr_iomux->dram_sdclk_1 = ddr->dram_sdclk_1; + + /* Address */ + mx6_ddr_iomux->dram_cas = ddr->dram_cas; + mx6_ddr_iomux->dram_ras = ddr->dram_ras; + mx6_grp_iomux->grp_addds = grp->grp_addds; + + /* Control */ + mx6_ddr_iomux->dram_reset = ddr->dram_reset; + mx6_ddr_iomux->dram_sdcke0 = ddr->dram_sdcke0; + mx6_ddr_iomux->dram_sdcke1 = ddr->dram_sdcke1; + mx6_ddr_iomux->dram_sdba2 = ddr->dram_sdba2; + mx6_ddr_iomux->dram_sdodt0 = ddr->dram_sdodt0; + mx6_ddr_iomux->dram_sdodt1 = ddr->dram_sdodt1; + mx6_grp_iomux->grp_ctlds = grp->grp_ctlds; + + /* Data Strobes */ + mx6_grp_iomux->grp_ddrmode_ctl = grp->grp_ddrmode_ctl; + mx6_ddr_iomux->dram_sdqs0 = ddr->dram_sdqs0; + mx6_ddr_iomux->dram_sdqs1 = ddr->dram_sdqs1; + if (width >= 32) { + mx6_ddr_iomux->dram_sdqs2 = ddr->dram_sdqs2; + mx6_ddr_iomux->dram_sdqs3 = ddr->dram_sdqs3; + } + if (width >= 64) { + mx6_ddr_iomux->dram_sdqs4 = ddr->dram_sdqs4; + mx6_ddr_iomux->dram_sdqs5 = ddr->dram_sdqs5; + mx6_ddr_iomux->dram_sdqs6 = ddr->dram_sdqs6; + mx6_ddr_iomux->dram_sdqs7 = ddr->dram_sdqs7; + } + + /* Data */ + mx6_grp_iomux->grp_ddrmode = grp->grp_ddrmode; + mx6_grp_iomux->grp_b0ds = grp->grp_b0ds; + mx6_grp_iomux->grp_b1ds = grp->grp_b1ds; + if (width >= 32) { + mx6_grp_iomux->grp_b2ds = grp->grp_b2ds; + mx6_grp_iomux->grp_b3ds = grp->grp_b3ds; + } + if (width >= 64) { + mx6_grp_iomux->grp_b4ds = grp->grp_b4ds; + mx6_grp_iomux->grp_b5ds = grp->grp_b5ds; + mx6_grp_iomux->grp_b6ds = grp->grp_b6ds; + mx6_grp_iomux->grp_b7ds = grp->grp_b7ds; + } + mx6_ddr_iomux->dram_dqm0 = ddr->dram_dqm0; + mx6_ddr_iomux->dram_dqm1 = ddr->dram_dqm1; + if (width >= 32) { + mx6_ddr_iomux->dram_dqm2 = ddr->dram_dqm2; + mx6_ddr_iomux->dram_dqm3 = ddr->dram_dqm3; + } + if (width >= 64) { + mx6_ddr_iomux->dram_dqm4 = ddr->dram_dqm4; + mx6_ddr_iomux->dram_dqm5 = ddr->dram_dqm5; + mx6_ddr_iomux->dram_dqm6 = ddr->dram_dqm6; + mx6_ddr_iomux->dram_dqm7 = ddr->dram_dqm7; + } +} + +/* Configure MX6SDL mmdc iomux */ +void mx6sdl_dram_iocfg(unsigned width, + const struct mx6sdl_iomux_ddr_regs *ddr, + const struct mx6sdl_iomux_grp_regs *grp) +{ + volatile struct mx6sdl_iomux_ddr_regs *mx6_ddr_iomux; + volatile struct mx6sdl_iomux_grp_regs *mx6_grp_iomux; + + mx6_ddr_iomux = (struct mx6sdl_iomux_ddr_regs *)MX6SDL_IOM_DDR_BASE; + mx6_grp_iomux = (struct mx6sdl_iomux_grp_regs *)MX6SDL_IOM_GRP_BASE; + + /* DDR IO Type */ + mx6_grp_iomux->grp_ddr_type = grp->grp_ddr_type; + mx6_grp_iomux->grp_ddrpke = grp->grp_ddrpke; + + /* Clock */ + mx6_ddr_iomux->dram_sdclk_0 = ddr->dram_sdclk_0; + mx6_ddr_iomux->dram_sdclk_1 = ddr->dram_sdclk_1; + + /* Address */ + mx6_ddr_iomux->dram_cas = ddr->dram_cas; + mx6_ddr_iomux->dram_ras = ddr->dram_ras; + mx6_grp_iomux->grp_addds = grp->grp_addds; + + /* Control */ + mx6_ddr_iomux->dram_reset = ddr->dram_reset; + mx6_ddr_iomux->dram_sdcke0 = ddr->dram_sdcke0; + mx6_ddr_iomux->dram_sdcke1 = ddr->dram_sdcke1; + mx6_ddr_iomux->dram_sdba2 = ddr->dram_sdba2; + mx6_ddr_iomux->dram_sdodt0 = ddr->dram_sdodt0; + mx6_ddr_iomux->dram_sdodt1 = ddr->dram_sdodt1; + mx6_grp_iomux->grp_ctlds = grp->grp_ctlds; + + /* Data Strobes */ + mx6_grp_iomux->grp_ddrmode_ctl = grp->grp_ddrmode_ctl; + mx6_ddr_iomux->dram_sdqs0 = ddr->dram_sdqs0; + mx6_ddr_iomux->dram_sdqs1 = ddr->dram_sdqs1; + if (width >= 32) { + mx6_ddr_iomux->dram_sdqs2 = ddr->dram_sdqs2; + mx6_ddr_iomux->dram_sdqs3 = ddr->dram_sdqs3; + } + if (width >= 64) { + mx6_ddr_iomux->dram_sdqs4 = ddr->dram_sdqs4; + mx6_ddr_iomux->dram_sdqs5 = ddr->dram_sdqs5; + mx6_ddr_iomux->dram_sdqs6 = ddr->dram_sdqs6; + mx6_ddr_iomux->dram_sdqs7 = ddr->dram_sdqs7; + } + + /* Data */ + mx6_grp_iomux->grp_ddrmode = grp->grp_ddrmode; + mx6_grp_iomux->grp_b0ds = grp->grp_b0ds; + mx6_grp_iomux->grp_b1ds = grp->grp_b1ds; + if (width >= 32) { + mx6_grp_iomux->grp_b2ds = grp->grp_b2ds; + mx6_grp_iomux->grp_b3ds = grp->grp_b3ds; + } + if (width >= 64) { + mx6_grp_iomux->grp_b4ds = grp->grp_b4ds; + mx6_grp_iomux->grp_b5ds = grp->grp_b5ds; + mx6_grp_iomux->grp_b6ds = grp->grp_b6ds; + mx6_grp_iomux->grp_b7ds = grp->grp_b7ds; + } + mx6_ddr_iomux->dram_dqm0 = ddr->dram_dqm0; + mx6_ddr_iomux->dram_dqm1 = ddr->dram_dqm1; + if (width >= 32) { + mx6_ddr_iomux->dram_dqm2 = ddr->dram_dqm2; + mx6_ddr_iomux->dram_dqm3 = ddr->dram_dqm3; + } + if (width >= 64) { + mx6_ddr_iomux->dram_dqm4 = ddr->dram_dqm4; + mx6_ddr_iomux->dram_dqm5 = ddr->dram_dqm5; + mx6_ddr_iomux->dram_dqm6 = ddr->dram_dqm6; + mx6_ddr_iomux->dram_dqm7 = ddr->dram_dqm7; + } +} + +/* + * 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 + */ +#define MR(val, ba, cmd, cs1) \ + ((val << 16) | (1 << 15) | (cmd << 4) | (cs1 << 3) | ba) +void mx6_dram_cfg(const struct mx6_ddr_sysinfo *i, + const struct mx6_mmdc_calibration *c, + const struct mx6_ddr3_cfg *m) +{ + volatile struct mmdc_p_regs *mmdc0; + volatile struct mmdc_p_regs *mmdc1; + 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; + + mmdc0 = (struct mmdc_p_regs *)MMDC_P0_BASE_ADDR; + mmdc1 = (struct mmdc_p_regs *)MMDC_P1_BASE_ADDR; + + /* 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 */ + mmdc0->mpzqhwctrl = (u32)0xa1390003; + if (i->dsize > 1) + mmdc1->mpzqhwctrl = (u32)0xa1390003; + + /* + * board-specific configuration: + * These values are determined empirically and vary per board layout + * see: + * appnote, ddr3 spreadsheet + */ + mmdc0->mpwldectrl0 = c->p0_mpwldectrl0; + mmdc0->mpwldectrl1 = c->p0_mpwldectrl1; + mmdc0->mpdgctrl0 = c->p0_mpdgctrl0; + mmdc0->mpdgctrl1 = c->p0_mpdgctrl1; + mmdc0->mprddlctl = c->p0_mprddlctl; + mmdc0->mpwrdlctl = c->p0_mpwrdlctl; + if (i->dsize > 1) { + mmdc1->mpwldectrl0 = c->p1_mpwldectrl0; + mmdc1->mpwldectrl1 = c->p1_mpwldectrl1; + mmdc1->mpdgctrl0 = c->p1_mpdgctrl0; + mmdc1->mpdgctrl1 = c->p1_mpdgctrl1; + mmdc1->mprddlctl = c->p1_mprddlctl; + mmdc1->mpwrdlctl = c->p1_mpwrdlctl; + } + + /* Read data DQ Byte0-3 delay */ + mmdc0->mprddqby0dl = (u32)0x33333333; + mmdc0->mprddqby1dl = (u32)0x33333333; + if (i->dsize > 0) { + mmdc0->mprddqby2dl = (u32)0x33333333; + mmdc0->mprddqby3dl = (u32)0x33333333; + } + if (i->dsize > 1) { + mmdc1->mprddqby0dl = (u32)0x33333333; + mmdc1->mprddqby1dl = (u32)0x33333333; + mmdc1->mprddqby2dl = (u32)0x33333333; + mmdc1->mprddqby3dl = (u32)0x33333333; + } + + /* complete calibration by forced measurement */ + mmdc0->mpmur0 = (u32)0x00000800; + if (i->dsize > 1) + mmdc1->mpmur0 = (u32)0x00000800; + + /* MMDC init */ + reg = (tcke << 16) | (tcksrx << 3) | tcksre; + mmdc0->mdpdc = reg; + reg = (taofpd << 27) | (taonpd << 24) | (tanpd << 20) | (taxpd << 16) | + (todtlon << 12) | (todt_idle_off << 4); + mmdc0->mdotc = reg; + + /* Timing configuration */ + reg = (trfc << 24) | (txs << 16) | (txp << 13) | (txpdll << 9) | + (tfaw << 4) | tcl; + mmdc0->mdcfg0 = reg; + reg = (trcd << 29) | (trp << 26) | (trc << 21) | (tras << 16) | + (1 << 15) | /* trpa */ + (twr << 9) | (tmrd << 5) | tcwl; + mmdc0->mdcfg1 = reg; + reg = (tdllk << 16) | (trtp << 6) | (twtr << 3) | trrd; + mmdc0->mdcfg2 = reg; + reg = (i->cs1_mirror << 19) | (i->walat << 16) | (i->bi_on << 12) | + (i->mif3_mode << 9) | (i->ralat << 6); + mmdc0->mdmisc = reg; + + /* configuration request */ + mmdc0->mdscr = (u32)(1 << 15); /* config request */ + mmdc0->mdrwd = (u32)0x000026d2; + reg = (txpr << 16) | (i->sde_to_rst << 8) | (i->rst_to_cke << 0); + mmdc0->mdor = reg; + + /* addressing */ + mmdc0->mdasp = CS0_END; + 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 */ + mmdc0->mdctl = reg; + + /* 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; + mmdc0->mdscr = (u32)MR(reg, 2, 3, cs); + /* MR3 */ + mmdc0->mdscr = (u32)MR(0, 3, 3, cs); + /* MR1 */ + reg = ((i->rtt_nom & 1) ? 1 : 0) << 2 | + ((i->rtt_nom & 2) ? 1 : 0) << 6; + mmdc0->mdscr = (u32)MR(reg, 1, 3, cs); + reg = ((tcl - 1) << 4) | /* CAS */ + (1 << 8) | /* DLL Reset */ + ((twr - 3) << 9); /* Write Recovery */ + /* MR0 */ + mmdc0->mdscr = (u32)MR(reg, 0, 3, cs); + /* ZQ calibration */ + reg = (1 << 10); + mmdc0->mdscr = (u32)MR(reg, 0, 4, cs); + } + + /* refresh control register */ + reg = (1 << 14) | /* REF_SEL: Periodic refresh cycles of 32kHz */ + (7 << 11); /* REFR: Refresh Rate - 8 refreshes */ + mmdc0->mdref = reg; + + /* MMDC Termination: rtt_nom:2 RZQ/2(120ohm), rtt_nom:1 RZQ/4(60ohm) */ + reg = (i->rtt_nom == 2) ? 0x00011117 : 0x00022227; + mmdc0->mpodtctrl = reg; + if (i->dsize > 1) + mmdc1->mpodtctrl = reg; + /* 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); + mmdc0->mdpdc = reg; /* SDCTL power down enabled */ + mmdc0->mapsr = (u32)0x00011006; /* ADOPT power down enabled */ + mmdc0->mdscr = (u32)0x00000000; /* init complete */ +}

Hi Tim,
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add functions for configuring MMDC iomux and configuration based on board-specific configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- split out mmdc and iomux structs into separate patch
arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 469 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 470 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..1536418 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -0,0 +1,469 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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>
Do you think that someone will want to use SPL on i.MX6 with support for only one of the variants?
It seems that this should be conditionally included if i.MX6DQ is supported by the board.
+/* Configure MX6DQ mmdc iomux */ +void mx6dq_dram_iocfg(unsigned width,
const struct mx6dq_iomux_ddr_regs *ddr,
const struct mx6dq_iomux_grp_regs *grp)
+{
- volatile struct mx6dq_iomux_ddr_regs *mx6_ddr_iomux;
...
Ditto for i.MX6SDL:
+/* Configure MX6SDL mmdc iomux */ +void mx6sdl_dram_iocfg(unsigned width,
const struct mx6sdl_iomux_ddr_regs *ddr,
const struct mx6sdl_iomux_grp_regs *grp)
+{
Regards,
Eric

On Tue, Apr 29, 2014 at 8:15 AM, Eric Nelson eric.nelson@boundarydevices.com wrote:
Hi Tim,
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add functions for configuring MMDC iomux and configuration based on board-specific configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- split out mmdc and iomux structs into separate patch
arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 469 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 470 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..1536418 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -0,0 +1,469 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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>
Do you think that someone will want to use SPL on i.MX6 with support for only one of the variants?
It seems that this should be conditionally included if i.MX6DQ is supported by the board.
Eric,
Yes - that makes sense. Someone could have a single CPU but have several memory variants. I'm not sure how much codespace it will save but things are tight at 64KB max.
I can wrap the functions and their calls with an:
#if defined(MX6QDL) || defined(MX6Q) || defined(MX6D)
+/* Configure MX6DQ mmdc iomux */ +void mx6dq_dram_iocfg(unsigned width,
const struct mx6dq_iomux_ddr_regs *ddr,
const struct mx6dq_iomux_grp_regs *grp)
+{
volatile struct mx6dq_iomux_ddr_regs *mx6_ddr_iomux;
...
Ditto for i.MX6SDL:
and:
#if defined(MX6QDL) || defined(MX6DL) || defined(MX6S)
Tim
+/* Configure MX6SDL mmdc iomux */ +void mx6sdl_dram_iocfg(unsigned width,
const struct mx6sdl_iomux_ddr_regs *ddr,
const struct mx6sdl_iomux_grp_regs *grp)
+{
Regards,
Eric

Hi Tim,
On 04/29/2014 11:19 AM, Tim Harvey wrote:
On Tue, Apr 29, 2014 at 8:15 AM, Eric Nelson eric.nelson@boundarydevices.com wrote:
Hi Tim,
<snip>
Do you think that someone will want to use SPL on i.MX6 with support for only one of the variants?
It seems that this should be conditionally included if i.MX6DQ is supported by the board.
Eric,
Yes - that makes sense. Someone could have a single CPU but have several memory variants. I'm not sure how much codespace it will save but things are tight at 64KB max.
I can wrap the functions and their calls with an:
#if defined(MX6QDL) || defined(MX6Q) || defined(MX6D)
Perfect.
+/* Configure MX6DQ mmdc iomux */ +void mx6dq_dram_iocfg(unsigned width,
const struct mx6dq_iomux_ddr_regs *ddr,
const struct mx6dq_iomux_grp_regs *grp)
+{
volatile struct mx6dq_iomux_ddr_regs *mx6_ddr_iomux;
...
Ditto for i.MX6SDL:
and:
#if defined(MX6QDL) || defined(MX6DL) || defined(MX6S)
Cool.

Hello,
On Tue, Apr 29, 2014 at 12:15 PM, Eric Nelson eric.nelson@boundarydevices.com wrote:
On 04/28/2014 01:17 PM, Tim Harvey wrote:
Add functions for configuring MMDC iomux and configuration based on board-specific configurations.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- split out mmdc and iomux structs into separate patch
arch/arm/cpu/armv7/mx6/Makefile | 1 + arch/arm/cpu/armv7/mx6/ddr.c | 469 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 470 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..1536418 --- /dev/null +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -0,0 +1,469 @@ +/*
- Copyright (C) 2014 Gateworks Corporation
- 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>
Do you think that someone will want to use SPL on i.MX6 with support for only one of the variants?
Sure, Falcon mode comes to my mind...

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 --- v2: - moved macros for declaring and using structs for array variant - removed non-related whitespace cleanup --- arch/arm/imx-common/iomux-v3.c | 19 +++++++++++++++---- arch/arm/include/asm/imx-common/iomux-v3.h | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 4 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..2f7a1cb 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -167,7 +167,22 @@ 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);
+/* macros for declaring and using pinmux array */ +#define IOMUX_PADS(x) (MX6Q_##x), (MX6DL_##x) +#define SETUP_IOMUX_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_IOMUX_PADS(x) \ + imx_iomux_v3_setup_multiple_pads_array(x, \ + ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2) + #endif /* __MACH_IOMUX_V3_H__*/

Hi Tim,
On 04/28/2014 01:17 PM, 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 don't think a blind reference to the previously proposed solution helps in understanding this patch, and an example would be more helpful.
Signed-off-by: Tim Harvey tharvey@gateworks.com
v2:
- moved macros for declaring and using structs for array variant
- removed non-related whitespace cleanup
arch/arm/imx-common/iomux-v3.c | 19 +++++++++++++++---- arch/arm/include/asm/imx-common/iomux-v3.h | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 4 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 }
It's odd that git generated removal and re-insertion of this bit:
-void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
unsigned count)
I think 'start_offs' would be clearer than 'list'.
The function name ..._array() also doesn't really capture what's going on here. Naming is hard though, and I'm not coming up with something else.
Perhaps 'sparse', 'skip', or alternate?
+/* 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..2f7a1cb 100644 --- a/arch/arm/include/asm/imx-common/iomux-v3.h +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -167,7 +167,22 @@ 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);
Ditto about function and parameter naming.
void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list, unsigned count);
It doesn't get any simpler than this:
+/* macros for declaring and using pinmux array */ +#define IOMUX_PADS(x) (MX6Q_##x), (MX6DL_##x)
In a similar vein to my comment about Patch 8, I do wonder if a minor extension of this will allow use with a single-variant board though.
We have some custom designs that really only function with one variant (usually i.MX6DQ) and it seems wrong to have the other variant included.
+#define SETUP_IOMUX_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_IOMUX_PADS(x) \
- imx_iomux_v3_setup_multiple_pads_array(x, \
- ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2)
- #endif /* __MACH_IOMUX_V3_H__*/
Please don't mis-interpret my comments as any form of Nack.
This patch moves the ball forward, and the approach of building two lists into one prevents duplication of tables quite nicely.
Regards,
Eric

On Tue, Apr 29, 2014 at 8:22 AM, Eric Nelson eric.nelson@boundarydevices.com wrote:
Hi Tim,
Hi Eric,
On 04/28/2014 01:17 PM, 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 don't think a blind reference to the previously proposed solution helps in understanding this patch, and an example would be more helpful.
agreed - will remove
<snip>
-void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
unsigned count)
I think 'start_offs' would be clearer than 'list'.
agreed - will change to 'start_offs'
The function name ..._array() also doesn't really capture what's going on here. Naming is hard though, and I'm not coming up with something else.
Perhaps 'sparse', 'skip', or alternate?
ya, I'm not sure anything else is more explanatory when we are doing something like this. Its bad enough that its likely difficult for someone to understand their first time through that we are doing this to eliminate multiple structs.
<snip>
+/* macros for declaring and using pinmux array */ +#define IOMUX_PADS(x) (MX6Q_##x), (MX6DL_##x)
In a similar vein to my comment about Patch 8, I do wonder if a minor extension of this will allow use with a single-variant board though.
for a single-variant one would just use the original IOMUX_PAD/imx_iomux_v3_setup_pad/imx_iomux_v3_setup_pad right?
We have some custom designs that really only function with one variant (usually i.MX6DQ) and it seems wrong to have the other variant included.
+#define SETUP_IOMUX_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_IOMUX_PADS(x) \
imx_iomux_v3_setup_multiple_pads_array(x, \
ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2)
- #endif /* __MACH_IOMUX_V3_H__*/
Please don't mis-interpret my comments as any form of Nack.
This patch moves the ball forward, and the approach of building two lists into one prevents duplication of tables quite nicely.
Regards,
Eric
Thanks for the review!
Tim

On 06/05/14 07:35, Tim Harvey wrote:
On Tue, Apr 29, 2014 at 8:22 AM, Eric Nelson eric.nelson@boundarydevices.com wrote:
<snip>
The function name ..._array() also doesn't really capture what's going on here. Naming is hard though, and I'm not coming up with something else.
Perhaps 'sparse', 'skip', or alternate?
ya, I'm not sure anything else is more explanatory when we are doing something like this. Its bad enough that its likely difficult for someone to understand their first time through that we are doing this to eliminate multiple structs.
Come to think of it, I don't think we need an _array() function at all. The list selection and stride size are IOMUX_PADS implementation details. It's not something we should expose to the function user. is_cpu_type() and ifdef(CONFIG_MX6QDL) can be used to decide the list and stride values inside imx_iomux_v3_setup_multiple_pads(), and then this function could be used for both single and multi cpu type situations.
<snip> >> +/* macros for declaring and using pinmux array */ >> +#define IOMUX_PADS(x) (MX6Q_##x), (MX6DL_##x) > > In a similar vein to my comment about Patch 8, I do wonder if a > minor extension of this will allow use with a single-variant > board though. for a single-variant one would just use the original IOMUX_PAD/imx_iomux_v3_setup_pad/imx_iomux_v3_setup_pad right?
They can, but then we don't get to use the same code for both situations. If we define two versions of IOMUX_PADS: one for multi cpu type, and one for single cpu type, then the pinmux arrays for both situations will be syntactically similar. When combined with my other suggestion, it will be very easy to take a U-Boot configured for one CPU type, and reconfigure it to support both CPU types.
We have some custom designs that really only function with one variant (usually i.MX6DQ) and it seems wrong to have the other variant included.
+#define SETUP_IOMUX_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_IOMUX_PADS(x) \
imx_iomux_v3_setup_multiple_pads_array(x, \
ARRAY_SIZE(x)/2, is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1, 2)
- #endif /* __MACH_IOMUX_V3_H__*/
Please don't mis-interpret my comments as any form of Nack.
This patch moves the ball forward, and the approach of building two lists into one prevents duplication of tables quite nicely.
Regards,
Eric
Thanks for the review!
Tim _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
-- Regards, Nikita Kiryanov

On Wed, May 7, 2014 at 9:59 AM, Nikita Kiryanov nikita@compulab.co.il wrote:
On 06/05/14 07:35, Tim Harvey wrote:
On Tue, Apr 29, 2014 at 8:22 AM, Eric Nelson eric.nelson@boundarydevices.com wrote:
<snip>
The function name ..._array() also doesn't really capture what's going on here. Naming is hard though, and I'm not coming up with something else.
Perhaps 'sparse', 'skip', or alternate?
ya, I'm not sure anything else is more explanatory when we are doing something like this. Its bad enough that its likely difficult for someone to understand their first time through that we are doing this to eliminate multiple structs.
Come to think of it, I don't think we need an _array() function at all. The list selection and stride size are IOMUX_PADS implementation details. It's not something we should expose to the function user. is_cpu_type() and ifdef(CONFIG_MX6QDL) can be used to decide the list and stride values inside imx_iomux_v3_setup_multiple_pads(), and then this function could be used for both single and multi cpu type situations.
<snip> >> >> +/* macros for declaring and using pinmux array */ >> +#define IOMUX_PADS(x) (MX6Q_##x), (MX6DL_##x) > > > In a similar vein to my comment about Patch 8, I do wonder if a > minor extension of this will allow use with a single-variant > board though.
for a single-variant one would just use the original IOMUX_PAD/imx_iomux_v3_setup_pad/imx_iomux_v3_setup_pad right?
They can, but then we don't get to use the same code for both situations. If we define two versions of IOMUX_PADS: one for multi cpu type, and one for single cpu type, then the pinmux arrays for both situations will be syntactically similar. When combined with my other suggestion, it will be very easy to take a U-Boot configured for one CPU type, and reconfigure it to support both CPU types.
Nikita,
Excellent idea - I've merged that idea into my new patchset that I will post shortly.
Tim

Split the read_eeprom function out so that it can be shared (ie with SPL)
Signed-off-by: Tim Harvey tharvey@gateworks.com --- board/gateworks/gw_ventana/Makefile | 2 +- board/gateworks/gw_ventana/eeprom.c | 89 +++++++++++++++++++++++++++++ board/gateworks/gw_ventana/gw_ventana.c | 89 +---------------------------- board/gateworks/gw_ventana/ventana_eeprom.h | 11 ++++ 4 files changed, 102 insertions(+), 89 deletions(-) create mode 100644 board/gateworks/gw_ventana/eeprom.c
diff --git a/board/gateworks/gw_ventana/Makefile b/board/gateworks/gw_ventana/Makefile index e8dab89..03bd1fd 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 eeprom.o
diff --git a/board/gateworks/gw_ventana/eeprom.c b/board/gateworks/gw_ventana/eeprom.c new file mode 100644 index 0000000..e90186e --- /dev/null +++ b/board/gateworks/gw_ventana/eeprom.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 Gateworks Corporation + * Author: Tim Harvey tharvey@gateworks.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> + +#include "gsc.h" +#include "ventana_eeprom.h" + +/* read ventana EEPROM, check for validity, and return baseboard type */ +int +read_eeprom(int bus, struct ventana_board_info *info) +{ + int i; + int chksum; + char baseboard; + int type; + unsigned char *buf = (unsigned char *)info; + + memset(info, 0, sizeof(*info)); + + /* + * 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(bus) && + 0 == i2c_probe(GSC_EEPROM_ADDR)) + break; + mdelay(1); + } + + /* read eeprom config section */ + if (gsc_i2c_read(GSC_EEPROM_ADDR, 0x00, 1, buf, sizeof(*info))) { + puts("EEPROM: Failed to read EEPROM\n"); + info->model[0] = 0; + return GW_UNKNOWN; + } + + /* sanity checks */ + if (info->model[0] != 'G' || info->model[1] != 'W') { + puts("EEPROM: Invalid Model in EEPROM\n"); + info->model[0] = 0; + return GW_UNKNOWN; + } + + /* validate checksum */ + for (chksum = 0, i = 0; i < sizeof(*info)-2; i++) + chksum += buf[i]; + if ((info->chksum[0] != chksum>>8) || + (info->chksum[1] != (chksum&0xff))) { + puts("EEPROM: Failed EEPROM checksum\n"); + info->model[0] = 0; + return GW_UNKNOWN; + } + + /* original GW5400-A prototype */ + baseboard = info->model[3]; + if (strncasecmp((const char *)info->model, "GW5400-A", 8) == 0) + baseboard = '0'; + + switch (baseboard) { + case '0': /* original GW5400-A prototype */ + type = GW54proto; + break; + case '1': + type = GW51xx; + break; + case '2': + type = GW52xx; + break; + case '3': + type = GW53xx; + break; + case '4': + type = GW54xx; + break; + default: + printf("EEPROM: Unknown model in EEPROM: %s\n", info->model); + type = GW_UNKNOWN; + break; + } + return type; +} diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index 2113740..3b6bc01 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -81,15 +81,6 @@ DECLARE_GLOBAL_DATA_PTR; */ static struct ventana_board_info ventana_info;
-enum { - GW54proto, /* original GW5400-A prototype */ - GW51xx, - GW52xx, - GW53xx, - GW54xx, - GW_UNKNOWN, -}; - int board_type;
/* UART1: Function varies per baseboard */ @@ -368,84 +359,6 @@ int board_eth_init(bd_t *bis) return 0; }
-/* read ventana EEPROM, check for validity, and return baseboard type */ -static int -read_eeprom(void) -{ - int i; - int chksum; - char baseboard; - int type; - struct ventana_board_info *info = &ventana_info; - unsigned char *buf = (unsigned char *)&ventana_info; - - memset(info, 0, sizeof(ventana_info)); - - /* - * 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; - mdelay(1); - } - - /* read eeprom config section */ - if (gsc_i2c_read(GSC_EEPROM_ADDR, 0x00, 1, buf, sizeof(ventana_info))) { - puts("EEPROM: Failed to read EEPROM\n"); - info->model[0] = 0; - return GW_UNKNOWN; - } - - /* sanity checks */ - if (info->model[0] != 'G' || info->model[1] != 'W') { - puts("EEPROM: Invalid Model in EEPROM\n"); - info->model[0] = 0; - return GW_UNKNOWN; - } - - /* validate checksum */ - for (chksum = 0, i = 0; i < sizeof(*info)-2; i++) - chksum += buf[i]; - if ((info->chksum[0] != chksum>>8) || - (info->chksum[1] != (chksum&0xff))) { - puts("EEPROM: Failed EEPROM checksum\n"); - info->model[0] = 0; - return GW_UNKNOWN; - } - - /* original GW5400-A prototype */ - baseboard = info->model[3]; - if (strncasecmp((const char *)info->model, "GW5400-A", 8) == 0) - baseboard = '0'; - - switch (baseboard) { - case '0': /* original GW5400-A prototype */ - type = GW54proto; - break; - case '1': - type = GW51xx; - break; - case '2': - type = GW52xx; - break; - case '3': - type = GW53xx; - break; - case '4': - type = GW54xx; - break; - default: - printf("EEPROM: Unknown model in EEPROM: %s\n", info->model); - type = GW_UNKNOWN; - break; - } - return type; -} - /* * Baseboard specific GPIO */ @@ -924,7 +837,7 @@ int board_init(void) setup_sata(); #endif /* read Gateworks EEPROM into global struct (used later) */ - board_type = read_eeprom(); + board_type = read_eeprom(I2C_GSC, &ventana_info);
/* board-specifc GPIO iomux */ if (board_type < GW_UNKNOWN) { diff --git a/board/gateworks/gw_ventana/ventana_eeprom.h b/board/gateworks/gw_ventana/ventana_eeprom.h index 434b604..5b065be 100644 --- a/board/gateworks/gw_ventana/ventana_eeprom.h +++ b/board/gateworks/gw_ventana/ventana_eeprom.h @@ -103,4 +103,15 @@ enum { EECONFIG_RES15, };
+enum { + GW54proto, /* original GW5400-A prototype */ + GW51xx, + GW52xx, + GW53xx, + GW54xx, + GW_UNKNOWN, +}; + +int read_eeprom(int bus, struct ventana_board_info *); + #endif

use the new iomux function and a macros to create a multi-dimensional array of iomux values without duplicating the defintions.
Signed-off-by: Tim Harvey tharvey@gateworks.com --- v2: - use macros that have been moved to iomux-v3.h --- board/gateworks/gw_ventana/gw_ventana.c | 493 ++++++++++++++++++++------------ 1 file changed, 311 insertions(+), 182 deletions(-)
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c index 3b6bc01..584762f 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -85,109 +85,149 @@ 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_PADS(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX_PADS(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_PADS(PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX_PADS(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 = MX6_PAD_KEY_COL3__I2C2_SCL | PC, - .gpio_mode = MX6_PAD_KEY_COL3__GPIO4_IO12 | PC, + .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 = MX6_PAD_KEY_ROW3__I2C2_SDA | PC, - .gpio_mode = MX6_PAD_KEY_ROW3__GPIO4_IO13 | PC, + .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 = 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 = 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 = 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 = 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 = MX6_PAD_GPIO_3__I2C3_SCL | PC, - .gpio_mode = MX6_PAD_GPIO_3__GPIO1_IO03 | PC, + .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 = MX6_PAD_GPIO_6__I2C3_SDA | PC, - .gpio_mode = MX6_PAD_GPIO_6__GPIO1_IO06 | PC, + .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_PADS(PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + /* CD */ + IOMUX_PADS(PAD_SD3_DAT5__GPIO7_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
/* 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_PADS(PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_TX_CTL__RGMII_TX_CTL | + MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_ENET_REF_CLK__ENET_TX_CLK | + MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)), + IOMUX_PADS(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_PADS(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_PADS(PAD_NANDF_CLE__NAND_CLE | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_ALE__NAND_ALE | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_WP_B__NAND_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_RB0__NAND_READY_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_CS0__NAND_CE0_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_SD4_CMD__NAND_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_SD4_CLK__NAND_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D0__NAND_DATA00 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D1__NAND_DATA01 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D2__NAND_DATA02 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D3__NAND_DATA03 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D4__NAND_DATA04 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D5__NAND_DATA05 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D6__NAND_DATA06 | MUX_PAD_CTRL(NO_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D7__NAND_DATA07 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
#ifdef CONFIG_CMD_NAND @@ -196,7 +236,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_IOMUX_PADS(nfc_pads);
/* config gpmi and bch clock to 100 MHz */ clrsetbits_le32(&mxc_ccm->cs2cdr, @@ -222,7 +262,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_IOMUX_PADS(enet_pads);
/* toggle PHY_RST# */ gpio_direction_output(GP_PHY_RST, 0); @@ -232,35 +272,36 @@ 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_IOMUX_PADS(uart1_pads); + SETUP_IOMUX_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_PADS(PAD_GPIO_1__USB_OTG_ID | MUX_PAD_CTRL(DIO_PAD_CTRL)), + IOMUX_PADS(PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(DIO_PAD_CTRL)), + /* OTG PWR */ + IOMUX_PADS(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_IOMUX_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_IOMUX_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_IOMUX_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); @@ -292,7 +333,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_IOMUX_PADS(usdhc3_pads); usdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); usdhc_cfg.max_bus_width = 4;
@@ -303,17 +344,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_PADS(PAD_EIM_D19__GPIO3_IO19 | MUX_PAD_CTRL(SPI_PAD_CTRL)), + IOMUX_PADS(PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL)), + IOMUX_PADS(PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL)), + IOMUX_PADS(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_IOMUX_PADS(ecspi1_pads); } #endif
@@ -366,118 +406,118 @@ int board_eth_init(bd_t *bis) /* 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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(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_PADS(PAD_ENET_TXD1__GPIO1_IO29 | MUX_PAD_CTRL(NO_PAD_CTRL)), };
/* @@ -485,9 +525,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; };
@@ -514,16 +554,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_PADS(PAD_GPIO_9__GPIO1_IO09) }, + IMX_GPIO_NR(1, 9), + { IOMUX_PADS(PAD_GPIO_9__PWM1_OUT) }, + 1 + }, + { + { IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX_PADS(PAD_SD4_DAT1__GPIO2_IO09) }, + IMX_GPIO_NR(2, 9), + { IOMUX_PADS(PAD_SD4_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX_PADS(PAD_SD4_DAT2__GPIO2_IO10) }, + IMX_GPIO_NR(2, 10), + { IOMUX_PADS(PAD_SD4_DAT2__PWM4_OUT) }, + 4 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -541,16 +597,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_PADS(PAD_SD1_DAT0__GPIO1_IO16) }, + IMX_GPIO_NR(1, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) }, + IMX_GPIO_NR(1, 17), + { IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX_PADS(PAD_SD1_CMD__GPIO1_IO18) }, + IMX_GPIO_NR(1, 18), + { IOMUX_PADS(PAD_SD1_CMD__PWM4_OUT) }, + 4 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -566,16 +638,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_PADS(PAD_SD1_DAT0__GPIO1_IO16) }, + IMX_GPIO_NR(1, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) }, + IMX_GPIO_NR(1, 17), + { IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX_PADS(PAD_SD1_CLK__GPIO1_IO20) }, + IMX_GPIO_NR(1, 20), + { 0, 0 }, + 0 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -593,16 +681,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_PADS(PAD_SD1_DAT0__GPIO1_IO16) }, + IMX_GPIO_NR(1, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) }, + IMX_GPIO_NR(1, 17), + { IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) }, + 3 + }, + { + {IOMUX_PADS(PAD_SD1_CLK__GPIO1_IO20) }, + IMX_GPIO_NR(1, 20), + { 0, 0 }, + 0 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -619,16 +723,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_PADS(PAD_GPIO_9__GPIO1_IO09) }, + IMX_GPIO_NR(1, 9), + { IOMUX_PADS(PAD_GPIO_9__PWM1_OUT) }, + 1 + }, + { + { IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) }, + IMX_GPIO_NR(1, 19), + { IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) }, + 2 + }, + { + { IOMUX_PADS(PAD_SD4_DAT1__GPIO2_IO09) }, + IMX_GPIO_NR(2, 9), + { IOMUX_PADS(PAD_SD4_DAT1__PWM3_OUT) }, + 3 + }, + { + { IOMUX_PADS(PAD_SD4_DAT2__GPIO2_IO10) }, + IMX_GPIO_NR(2, 10), + { IOMUX_PADS(PAD_SD4_DAT2__PWM4_OUT) }, + 4 + }, }, .leds = { IMX_GPIO_NR(4, 6), @@ -718,6 +838,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)) @@ -732,14 +853,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)); } } @@ -759,9 +880,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; } @@ -807,7 +929,6 @@ int dram_init(void) { gd->ram_size = get_ram_size((void *)PHYS_SDRAM, CONFIG_DDR_MB*1024*1024); - return 0; }
@@ -829,9 +950,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(); @@ -840,11 +967,13 @@ int board_init(void) board_type = read_eeprom(I2C_GSC, &ventana_info);
/* board-specifc GPIO iomux */ + SETUP_IOMUX_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;

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 or MTD depending on boot device 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 --- v2: - remove missing/unnecessary include - revert mtdparts change - use imx_ddr_size() which uses MMDC configuration to determine mem size explicitly - add support for MX6SOLO and MX6DUAL - set CS0_END for 4GB so get_ram_size() works - updated DDR3 calibration values for ventana boards - fixed build issue - only compile spl if doing spl build - fixed line length issue in README - remove CONFIG_SPL* conditions and conditionally compile instead - removed prints for CPU type and DRAM size/width - uboot will print these later - removed unused gw_ventana_spl.cfg - use common read_eeprom function - added MMC support to SPL --- board/gateworks/gw_ventana/Makefile | 1 + board/gateworks/gw_ventana/README | 92 ++++--- board/gateworks/gw_ventana/gw_ventana.c | 9 +- board/gateworks/gw_ventana/gw_ventana.cfg | 15 - board/gateworks/gw_ventana/gw_ventana_spl.c | 407 ++++++++++++++++++++++++++++ boards.cfg | 6 +- include/configs/gw_ventana.h | 11 + 7 files changed, 485 insertions(+), 56 deletions(-) create mode 100644 board/gateworks/gw_ventana/gw_ventana_spl.c
diff --git a/board/gateworks/gw_ventana/Makefile b/board/gateworks/gw_ventana/Makefile index 03bd1fd..33a1788 100644 --- a/board/gateworks/gw_ventana/Makefile +++ b/board/gateworks/gw_ventana/Makefile @@ -7,4 +7,5 @@ #
obj-y := gw_ventana.o gsc.o eeprom.o +obj-$(CONFIG_SPL_BUILD) += gw_ventana_spl.o
diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README index 9e697d6..888657c 100644 --- a/board/gateworks/gw_ventana/README +++ b/board/gateworks/gw_ventana/README @@ -3,53 +3,81 @@ 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 584762f..ee2b203 100644 --- a/board/gateworks/gw_ventana/gw_ventana.c +++ b/board/gateworks/gw_ventana/gw_ventana.c @@ -927,8 +927,7 @@ int board_early_init_f(void)
int dram_init(void) { - gd->ram_size = get_ram_size((void *)PHYS_SDRAM, - CONFIG_DDR_MB*1024*1024); + gd->ram_size = imx_ddr_size(); return 0; }
@@ -1071,9 +1070,11 @@ int misc_init_r(void) * env scripts will try loading each from most specific to * least. */ - if (is_cpu_type(MXC_CPU_MX6Q)) + if (is_cpu_type(MXC_CPU_MX6Q) || + is_cpu_type(MXC_CPU_MX6D)) cputype = "imx6q"; - else if (is_cpu_type(MXC_CPU_MX6DL)) + else if (is_cpu_type(MXC_CPU_MX6DL) || + is_cpu_type(MXC_CPU_MX6SOLO)) cputype = "imx6dl"; memset(str, 0, sizeof(str)); for (i = 0; i < (sizeof(str)-1) && info->model[i]; i++) 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..d6c99f8 --- /dev/null +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2014 Gateworks Corporation + * 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.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> +#include <spl.h> + +#include "ventana_eeprom.h" + +DECLARE_GLOBAL_DATA_PTR; + +#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); +} + +/* configure MX6Q/DUAL mmdc DDR io registers */ +struct mx6dq_iomux_ddr_regs mx6dq_ddr_ioregs = { + /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ + .dram_sdclk_0 = 0x00020030, + .dram_sdclk_1 = 0x00020030, + .dram_cas = 0x00020030, + .dram_ras = 0x00020030, + .dram_reset = 0x00020030, + /* SDCKE[0:1]: 100k pull-up */ + .dram_sdcke0 = 0x00003000, + .dram_sdcke1 = 0x00003000, + /* SDBA2: pull-up disabled */ + .dram_sdba2 = 0x00000000, + /* SDODT[0:1]: 100k pull-up, 40 ohm */ + .dram_sdodt0 = 0x00003030, + .dram_sdodt1 = 0x00003030, + /* SDQS[0:7]: Differential input, 40 ohm */ + .dram_sdqs0 = 0x00000030, + .dram_sdqs1 = 0x00000030, + .dram_sdqs2 = 0x00000030, + .dram_sdqs3 = 0x00000030, + .dram_sdqs4 = 0x00000030, + .dram_sdqs5 = 0x00000030, + .dram_sdqs6 = 0x00000030, + .dram_sdqs7 = 0x00000030, + + /* DQM[0:7]: Differential input, 40 ohm */ + .dram_dqm0 = 0x00020030, + .dram_dqm1 = 0x00020030, + .dram_dqm2 = 0x00020030, + .dram_dqm3 = 0x00020030, + .dram_dqm4 = 0x00020030, + .dram_dqm5 = 0x00020030, + .dram_dqm6 = 0x00020030, + .dram_dqm7 = 0x00020030, +}; + +/* configure MX6Q/DUAL mmdc GRP io registers */ +struct mx6dq_iomux_grp_regs mx6dq_grp_ioregs = { + /* DDR3 */ + .grp_ddr_type = 0x000c0000, + .grp_ddrmode_ctl = 0x00020000, + /* disable DDR pullups */ + .grp_ddrpke = 0x00000000, + /* ADDR[00:16], SDBA[0:1]: 40 ohm */ + .grp_addds = 0x00000030, + /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ + .grp_ctlds = 0x00000030, + /* DATA[00:63]: Differential input, 40 ohm */ + .grp_ddrmode = 0x00020000, + .grp_b0ds = 0x00000030, + .grp_b1ds = 0x00000030, + .grp_b2ds = 0x00000030, + .grp_b3ds = 0x00000030, + .grp_b4ds = 0x00000030, + .grp_b5ds = 0x00000030, + .grp_b6ds = 0x00000030, + .grp_b7ds = 0x00000030, +}; + +/* configure MX6SOLO/DUALLITE mmdc DDR io registers */ +struct mx6sdl_iomux_ddr_regs mx6sdl_ddr_ioregs = { + /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ + .dram_sdclk_0 = 0x00020030, + .dram_sdclk_1 = 0x00020030, + .dram_cas = 0x00020030, + .dram_ras = 0x00020030, + .dram_reset = 0x00020030, + /* SDCKE[0:1]: 100k pull-up */ + .dram_sdcke0 = 0x00003000, + .dram_sdcke1 = 0x00003000, + /* SDBA2: pull-up disabled */ + .dram_sdba2 = 0x00000000, + /* SDODT[0:1]: 100k pull-up, 40 ohm */ + .dram_sdodt0 = 0x00003030, + .dram_sdodt1 = 0x00003030, + /* SDQS[0:7]: Differential input, 40 ohm */ + .dram_sdqs0 = 0x00000030, + .dram_sdqs1 = 0x00000030, + .dram_sdqs2 = 0x00000030, + .dram_sdqs3 = 0x00000030, + .dram_sdqs4 = 0x00000030, + .dram_sdqs5 = 0x00000030, + .dram_sdqs6 = 0x00000030, + .dram_sdqs7 = 0x00000030, + + /* DQM[0:7]: Differential input, 40 ohm */ + .dram_dqm0 = 0x00020030, + .dram_dqm1 = 0x00020030, + .dram_dqm2 = 0x00020030, + .dram_dqm3 = 0x00020030, + .dram_dqm4 = 0x00020030, + .dram_dqm5 = 0x00020030, + .dram_dqm6 = 0x00020030, + .dram_dqm7 = 0x00020030, +}; + +/* configure MX6SOLO/DUALLITE mmdc GRP io registers */ +struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = { + /* DDR3 */ + .grp_ddr_type = 0x000c0000, + /* SDQS[0:7]: Differential input, 40 ohm */ + .grp_ddrmode_ctl = 0x00020000, + /* disable DDR pullups */ + .grp_ddrpke = 0x00000000, + /* ADDR[00:16], SDBA[0:1]: 40 ohm */ + .grp_addds = 0x00000030, + /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ + .grp_ctlds = 0x00000030, + /* DATA[00:63]: Differential input, 40 ohm */ + .grp_ddrmode = 0x00020000, + .grp_b0ds = 0x00000030, + .grp_b1ds = 0x00000030, + .grp_b2ds = 0x00000030, + .grp_b3ds = 0x00000030, + .grp_b4ds = 0x00000030, + .grp_b5ds = 0x00000030, + .grp_b6ds = 0x00000030, + .grp_b7ds = 0x00000030, +}; + +/* 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 gw54xxq_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x00190018, + .p0_mpwldectrl1 = 0x0021001D, + .p1_mpwldectrl0 = 0x00160027, + .p1_mpwldectrl1 = 0x0012001E, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x43370346, + .p0_mpdgctrl1 = 0x032A0321, + .p1_mpdgctrl0 = 0x433A034D, + .p1_mpdgctrl1 = 0x032F0235, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x3C313539, + .p1_mprddlctl = 0x37333140, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x37393C38, + .p1_mpwrdlctl = 0x42334538, +}; + +/* GW53xx specific calibration */ +static struct mx6_mmdc_calibration gw53xxq_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x00160013, + .p0_mpwldectrl1 = 0x00090024, + .p1_mpwldectrl0 = 0x001F0018, + .p1_mpwldectrl1 = 0x000C001C, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x433A034C, + .p0_mpdgctrl1 = 0x0336032F, + .p1_mpdgctrl0 = 0x4343034A, + .p1_mpdgctrl1 = 0x03370222, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x3F343638, + .p1_mprddlctl = 0x38373442, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x343A3E39, + .p1_mpwrdlctl = 0x44344239, +}; +static struct mx6_mmdc_calibration gw53xxdl_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x003C003C, + .p0_mpwldectrl1 = 0x00330038, + .p1_mpwldectrl0 = 0x001F002A, + .p1_mpwldectrl1 = 0x0022003F, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x42410244, + .p0_mpdgctrl1 = 0x022D022D, + .p1_mpdgctrl0 = 0x4234023A, + .p1_mpdgctrl1 = 0x021C0228, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x484A4C4B, + .p1_mprddlctl = 0x4B4D4E4B, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x33342B32, + .p1_mpwrdlctl = 0x3933332B, +}; + +/* GW52xx specific calibration */ +static struct mx6_mmdc_calibration gw52xxdl_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x0040003F, + .p0_mpwldectrl1 = 0x00370037, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x42420244, + .p0_mpdgctrl1 = 0x022F022F, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x49464B4A, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x32362C32, +}; + +/* GW51xx specific calibration */ +static struct mx6_mmdc_calibration gw51xxq_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x00150016, + .p0_mpwldectrl1 = 0x001F0017, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x433D034D, + .p0_mpdgctrl1 = 0x033D032F, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x3F313639, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x33393F36, +}; + +static struct mx6_mmdc_calibration gw51xxdl_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x003D003F, + .p0_mpwldectrl1 = 0x002F0038, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x423A023A, + .p0_mpdgctrl1 = 0x022A0228, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x48494C4C, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x34352D31, +}; + +static void spl_dram_init(int width, int size, int board_model) +{ + struct mx6_ddr3_cfg *mem = &mt41k128m16jt_125; + struct mx6_mmdc_calibration *calib; + struct mx6_ddr_sysinfo sysinfo = { + /* width of data bus:0=16,1=32,2=64 */ + .dsize = width/32, + /* config for full 4GB range so that get_mem_size() works */ + .cs_density = 32, /* 32Gb per CS */ + /* 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) */ + }; + + /* + * 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 (board_model) { + default: + case GW51xx: + if (is_cpu_type(MXC_CPU_MX6Q)) + calib = &gw51xxq_mmdc_calib; + else + calib = &gw51xxdl_mmdc_calib; + break; + case GW52xx: + calib = &gw52xxdl_mmdc_calib; + break; + case GW53xx: + if (is_cpu_type(MXC_CPU_MX6Q)) + calib = &gw53xxq_mmdc_calib; + else + calib = &gw53xxdl_mmdc_calib; + break; + case GW54xx: + calib = &gw54xxq_mmdc_calib; + break; + } + + if (is_cpu_type(MXC_CPU_MX6Q)) + mx6dq_dram_iocfg(width, &mx6dq_ddr_ioregs, + &mx6dq_grp_ioregs); + else + mx6sdl_dram_iocfg(width, &mx6sdl_ddr_ioregs, + &mx6sdl_grp_ioregs); + mx6_dram_cfg(&sysinfo, calib, mem); +} + +/* + * 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) +{ + struct ventana_board_info ventana_info; + int board_model; + + /* iomux and setup of i2c */ + i2c_setup_iomux(); + timer_init(); + board_model = read_eeprom(I2C_GSC, &ventana_info); + + /* provide some some default: 32bit 128MB */ + if (GW_UNKNOWN == board_model) { + ventana_info.sdram_width = 2; + ventana_info.sdram_size = 3; + } + spl_dram_init(8 << ventana_info.sdram_width, + 16 << ventana_info.sdram_size, + board_model); + + 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(); + + board_init_r(NULL, 0); +} + +void reset_cpu(ulong addr) +{ +} diff --git a/boards.cfg b/boards.cfg index c83aff3..9119e24 100644 --- a/boards.cfg +++ b/boards.cfg @@ -322,11 +322,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/configs/gw_ventana.h b/include/configs/gw_ventana.h index 3398390..cd53737 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_FAT_SUPPORT +/* +#define CONFIG_SPL_SATA_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 */

On Mon, Apr 28, 2014 at 1:17 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 or MTD depending on boot device and jump to it
This allows for a single SPL+u-boot.img to replace the previous multiple board configurations.
<snip>
+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);
+}
<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) +{
struct ventana_board_info ventana_info;
int board_model;
/* iomux and setup of i2c */
i2c_setup_iomux();
timer_init();
board_model = read_eeprom(I2C_GSC, &ventana_info);
/* provide some some default: 32bit 128MB */
if (GW_UNKNOWN == board_model) {
ventana_info.sdram_width = 2;
ventana_info.sdram_size = 3;
}
spl_dram_init(8 << ventana_info.sdram_width,
16 << ventana_info.sdram_size,
board_model);
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();
board_init_r(NULL, 0);
+}
Stefano / York,
While preparing for a v3 patch series of my IMX6 SPL bootloader, I find that commit dec1861be90c948ea9fb771927d3d26a994d2e20 [1] breaks the above code because gd is now needed within setup_i2c.
I've always been a bit fuzzy on the order of the above calls so I dug through the code and I think I understand things better. Please correct any wrong assumptions I'm making below: - assignment to gd should 'always' be first (before anything needs it, so why not do it first) - arch_cpu_init() should go next as this sets up very low level CPU/SoC resources (in this case AIPS config and watchdog disable) - board_early_init_f() should be next as that sets up any board-specific iomux - any additional iomux necessary for SPL should go next (I take care of i2c iomux and setup here) - timer_init() next as you need a timer for UART and mxc i2c (for delays and busy checks) - preloader_console_init() next as we are now able to send something over the UART (this gives me early debug for sdram config now too!) - sdram setup goes next - after sdram is setup, the bss can be cleared - board_init_r - pass over to generic SPL code which will load/call an image based on boot device
So, if the above is correct, I should rework the above function as follows:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata;
/* setup AIPS and disable watchdog */ arch_cpu_init();
/* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux();
/* setup GP timer */ timer_init();
/* UART clocks enabled and gd valid - init serial console */ preloader_console_init();
/* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info);
/* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; }
/* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model);
/* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start);
/* load/boot image from boot device */ board_init_r(NULL, 0); }
Does this make sense?
Thanks,
Tim
[1] - http://git.denx.de/?p=u-boot.git;a=commitdiff;h=dec1861be90c948ea9fb771927d3...
+void reset_cpu(ulong addr) +{ +} diff --git a/boards.cfg b/boards.cfg index c83aff3..9119e24 100644 --- a/boards.cfg +++ b/boards.cfg @@ -322,11 +322,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/configs/gw_ventana.h b/include/configs/gw_ventana.h index 3398390..cd53737 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_FAT_SUPPORT +/* +#define CONFIG_SPL_SATA_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 */
1.8.3.2

On 05/06/2014 11:18 AM, Tim Harvey wrote:
On Mon, Apr 28, 2014 at 1:17 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 or MTD depending on boot device and jump to it
This allows for a single SPL+u-boot.img to replace the previous multiple board configurations.
<snip> > + > +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); > +} > + <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) > +{ > + struct ventana_board_info ventana_info; > + int board_model; > + > + /* iomux and setup of i2c */ > + i2c_setup_iomux(); > + timer_init(); > + board_model = read_eeprom(I2C_GSC, &ventana_info); > + > + /* provide some some default: 32bit 128MB */ > + if (GW_UNKNOWN == board_model) { > + ventana_info.sdram_width = 2; > + ventana_info.sdram_size = 3; > + } > + spl_dram_init(8 << ventana_info.sdram_width, > + 16 << ventana_info.sdram_size, > + board_model); > + > + 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(); > + > + board_init_r(NULL, 0); > +}
Stefano / York,
While preparing for a v3 patch series of my IMX6 SPL bootloader, I find that commit dec1861be90c948ea9fb771927d3d26a994d2e20 [1] breaks the above code because gd is now needed within setup_i2c.
I've always been a bit fuzzy on the order of the above calls so I dug through the code and I think I understand things better. Please correct any wrong assumptions I'm making below:
- assignment to gd should 'always' be first (before anything needs
it, so why not do it first)
- arch_cpu_init() should go next as this sets up very low level
CPU/SoC resources (in this case AIPS config and watchdog disable)
- board_early_init_f() should be next as that sets up any board-specific iomux
- any additional iomux necessary for SPL should go next (I take care
of i2c iomux and setup here)
- timer_init() next as you need a timer for UART and mxc i2c (for
delays and busy checks)
- preloader_console_init() next as we are now able to send something
over the UART (this gives me early debug for sdram config now too!)
- sdram setup goes next
- after sdram is setup, the bss can be cleared
- board_init_r - pass over to generic SPL code which will load/call
an image based on boot device
So, if the above is correct, I should rework the above function as follows:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
Does this make sense?
Tim,
I agree gd should be set first if the memory is available. My previous change to this i2c driver was to make sure it works without DRAM. Since it uses a data structure, it has no other place to go.
York

Hello Tim,
On di, 2014-05-06 at 11:18 -0700, Tim Harvey wrote:
On Mon, Apr 28, 2014 at 1:17 PM, Tim Harvey tharvey@gateworks.com wrote:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
Does this make sense?
Since Crt0.S already created gd on the stack before calling board_init_f, can't the assignment of gd not simply be removed? Is there anything special about gdata?
Regards, Jeroen

On Tue, May 6, 2014 at 12:11 PM, Jeroen Hofstee dasuboot@myspectrum.nl wrote:
Hello Tim,
On di, 2014-05-06 at 11:18 -0700, Tim Harvey wrote:
On Mon, Apr 28, 2014 at 1:17 PM, Tim Harvey tharvey@gateworks.com wrote:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
Does this make sense?
Since Crt0.S already created gd on the stack before calling board_init_f, can't the assignment of gd not simply be removed? Is there anything special about gdata?
Regards, Jeroen
Jeroen,
That does make sense, but what I find is that York's ocmmit dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked and its not. This causes bus_i2c_init to skip its initialization because p->base is not zero.
York, does this make sense? Your patch creates a dependence on gd->srdata being blank which isn't the case with the SRAM when booting from the IMX6 boot rom.
Tim

On 05/06/2014 04:35 PM, Tim Harvey wrote:
On Tue, May 6, 2014 at 12:11 PM, Jeroen Hofstee dasuboot@myspectrum.nl wrote:
Hello Tim,
<snip>
Since Crt0.S already created gd on the stack before calling board_init_f, can't the assignment of gd not simply be removed? Is there anything special about gdata?
Regards, Jeroen
Jeroen,
That does make sense, but what I find is that York's ocmmit dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked and its not. This causes bus_i2c_init to skip its initialization because p->base is not zero.
York, does this make sense? Your patch creates a dependence on gd->srdata being blank which isn't the case with the SRAM when booting from the IMX6 boot rom.
GD should be cleared (zeroed). Then we don't have this problem. Whoever sets up gd (board_int_f, cpu_init_f, or others) should make sure gd is cleared. Why isn't it the case for IMX6 boot rom?
York

Hi,
On wo, 2014-05-07 at 09:14 -0700, York Sun wrote:
<snip> >> >> Since Crt0.S already created gd on the stack before calling >> board_init_f, can't the assignment of gd not simply be removed? >> Is there anything special about gdata? > > That does make sense, but what I find is that York's ocmmit > dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked > and its not. This causes bus_i2c_init to skip its initialization > because p->base is not zero. > > York, does this make sense? Your patch creates a dependence on > gd->srdata being blank which isn't the case with the SRAM when booting > from the IMX6 boot rom. >
GD should be cleared (zeroed). Then we don't have this problem. Whoever sets up gd (board_int_f, cpu_init_f, or others) should make sure gd is cleared. Why isn't it the case for IMX6 boot rom?
Seems fine to me. Albert, any objection against zeroing gd out in crt0.S?
And if not, shouldn't the same be done for arm64.
Jeroen

On Wed, May 7, 2014 at 9:14 AM, York Sun yorksun@freescale.com wrote:
On 05/06/2014 04:35 PM, Tim Harvey wrote:
On Tue, May 6, 2014 at 12:11 PM, Jeroen Hofstee dasuboot@myspectrum.nl wrote:
Hello Tim,
<snip> >> >> Since Crt0.S already created gd on the stack before calling >> board_init_f, can't the assignment of gd not simply be removed? >> Is there anything special about gdata? >> >> Regards, >> Jeroen >> >> > > Jeroen, > > That does make sense, but what I find is that York's ocmmit > dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked > and its not. This causes bus_i2c_init to skip its initialization > because p->base is not zero. > > York, does this make sense? Your patch creates a dependence on > gd->srdata being blank which isn't the case with the SRAM when booting > from the IMX6 boot rom. >
GD should be cleared (zeroed). Then we don't have this problem. Whoever sets up gd (board_int_f, cpu_init_f, or others) should make sure gd is cleared. Why isn't it the case for IMX6 boot rom?
York
York,
crt0.S is mapping gd to where the SPL stack pointer is defined, which is where Freescale says its stack pointer is for its firmware BOOT ROM, so its initial data will be dependent on what the BOOT ROM did.
I think the right solution is to have crt0.S zero it out.
Tim

On 05/07/2014 01:27 PM, Tim Harvey wrote:
On Wed, May 7, 2014 at 9:14 AM, York Sun yorksun@freescale.com wrote:
On 05/06/2014 04:35 PM, Tim Harvey wrote:
On Tue, May 6, 2014 at 12:11 PM, Jeroen Hofstee dasuboot@myspectrum.nl wrote:
Hello Tim,
<snip> >> >> Since Crt0.S already created gd on the stack before calling >> board_init_f, can't the assignment of gd not simply be removed? >> Is there anything special about gdata? >> >> Regards, >> Jeroen >> >> > > Jeroen, > > That does make sense, but what I find is that York's ocmmit > dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked > and its not. This causes bus_i2c_init to skip its initialization > because p->base is not zero. > > York, does this make sense? Your patch creates a dependence on > gd->srdata being blank which isn't the case with the SRAM when booting > from the IMX6 boot rom. >
GD should be cleared (zeroed). Then we don't have this problem. Whoever sets up gd (board_int_f, cpu_init_f, or others) should make sure gd is cleared. Why isn't it the case for IMX6 boot rom?
York
York,
crt0.S is mapping gd to where the SPL stack pointer is defined, which is where Freescale says its stack pointer is for its firmware BOOT ROM, so its initial data will be dependent on what the BOOT ROM did.
I think the right solution is to have crt0.S zero it out.
Either crt0.S, or somewhere before gd is used for the first time. Can it be done in board_init_f()?
York

On Wed, May 7, 2014 at 1:29 PM, York Sun yorksun@freescale.com wrote:
On 05/07/2014 01:27 PM, Tim Harvey wrote:
On Wed, May 7, 2014 at 9:14 AM, York Sun yorksun@freescale.com wrote:
On 05/06/2014 04:35 PM, Tim Harvey wrote:
On Tue, May 6, 2014 at 12:11 PM, Jeroen Hofstee dasuboot@myspectrum.nl wrote:
Hello Tim,
<snip> >> >> Since Crt0.S already created gd on the stack before calling >> board_init_f, can't the assignment of gd not simply be removed? >> Is there anything special about gdata? >> >> Regards, >> Jeroen >> >> > > Jeroen, > > That does make sense, but what I find is that York's ocmmit > dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked > and its not. This causes bus_i2c_init to skip its initialization > because p->base is not zero. > > York, does this make sense? Your patch creates a dependence on > gd->srdata being blank which isn't the case with the SRAM when booting > from the IMX6 boot rom. >
GD should be cleared (zeroed). Then we don't have this problem. Whoever sets up gd (board_int_f, cpu_init_f, or others) should make sure gd is cleared. Why isn't it the case for IMX6 boot rom?
York
York,
crt0.S is mapping gd to where the SPL stack pointer is defined, which is where Freescale says its stack pointer is for its firmware BOOT ROM, so its initial data will be dependent on what the BOOT ROM did.
I think the right solution is to have crt0.S zero it out.
Either crt0.S, or somewhere before gd is used for the first time. Can it be done in board_init_f()?
York
It makes more sense to do it in crt0.S so that all boards don't have to do it and can make the assumption that it is cleared.
Tim

On 05/07/2014 01:35 PM, Tim Harvey wrote:
On Wed, May 7, 2014 at 1:29 PM, York Sun yorksun@freescale.com wrote:
On 05/07/2014 01:27 PM, Tim Harvey wrote:
On Wed, May 7, 2014 at 9:14 AM, York Sun yorksun@freescale.com wrote:
On 05/06/2014 04:35 PM, Tim Harvey wrote:
On Tue, May 6, 2014 at 12:11 PM, Jeroen Hofstee dasuboot@myspectrum.nl wrote:
Hello Tim,
<snip> >> >> Since Crt0.S already created gd on the stack before calling >> board_init_f, can't the assignment of gd not simply be removed? >> Is there anything special about gdata? >> >> Regards, >> Jeroen >> >> > > Jeroen, > > That does make sense, but what I find is that York's ocmmit > dec1861be90c948ea9fb771927d3d26a994d2e20 requires that gd be blanked > and its not. This causes bus_i2c_init to skip its initialization > because p->base is not zero. > > York, does this make sense? Your patch creates a dependence on > gd->srdata being blank which isn't the case with the SRAM when booting > from the IMX6 boot rom. >
GD should be cleared (zeroed). Then we don't have this problem. Whoever sets up gd (board_int_f, cpu_init_f, or others) should make sure gd is cleared. Why isn't it the case for IMX6 boot rom?
York
York,
crt0.S is mapping gd to where the SPL stack pointer is defined, which is where Freescale says its stack pointer is for its firmware BOOT ROM, so its initial data will be dependent on what the BOOT ROM did.
I think the right solution is to have crt0.S zero it out.
Either crt0.S, or somewhere before gd is used for the first time. Can it be done in board_init_f()?
York
It makes more sense to do it in crt0.S so that all boards don't have to do it and can make the assumption that it is cleared.
No objection as far as it is cleared.
York

Hi Tim,
On 06/05/2014 20:18, Tim Harvey wrote:
Stefano / York,
While preparing for a v3 patch series of my IMX6 SPL bootloader, I find that commit dec1861be90c948ea9fb771927d3d26a994d2e20 [1] breaks the above code because gd is now needed within setup_i2c.
I've always been a bit fuzzy on the order of the above calls so I dug through the code and I think I understand things better. Please correct any wrong assumptions I'm making below:
- assignment to gd should 'always' be first (before anything needs
it, so why not do it first)
- arch_cpu_init() should go next as this sets up very low level
CPU/SoC resources (in this case AIPS config and watchdog disable)
- board_early_init_f() should be next as that sets up any board-specific iomux
- any additional iomux necessary for SPL should go next (I take care
of i2c iomux and setup here)
- timer_init() next as you need a timer for UART and mxc i2c (for
delays and busy checks)
- preloader_console_init() next as we are now able to send something
over the UART (this gives me early debug for sdram config now too!)
- sdram setup goes next
- after sdram is setup, the bss can be cleared
- board_init_r - pass over to generic SPL code which will load/call
an image based on boot device
I think your analyses is correct.
So, if the above is correct, I should rework the above function as follows:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
It seems reasonable, go on this way.
Regards, Stefano

On Wed, May 7, 2014 at 2:29 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
On 06/05/2014 20:18, Tim Harvey wrote:
Stefano / York,
While preparing for a v3 patch series of my IMX6 SPL bootloader, I find that commit dec1861be90c948ea9fb771927d3d26a994d2e20 [1] breaks the above code because gd is now needed within setup_i2c.
I've always been a bit fuzzy on the order of the above calls so I dug through the code and I think I understand things better. Please correct any wrong assumptions I'm making below:
- assignment to gd should 'always' be first (before anything needs
it, so why not do it first)
- arch_cpu_init() should go next as this sets up very low level
CPU/SoC resources (in this case AIPS config and watchdog disable)
- board_early_init_f() should be next as that sets up any board-specific iomux
- any additional iomux necessary for SPL should go next (I take care
of i2c iomux and setup here)
- timer_init() next as you need a timer for UART and mxc i2c (for
delays and busy checks)
- preloader_console_init() next as we are now able to send something
over the UART (this gives me early debug for sdram config now too!)
- sdram setup goes next
- after sdram is setup, the bss can be cleared
- board_init_r - pass over to generic SPL code which will load/call
an image based on boot device
I think your analyses is correct.
So, if the above is correct, I should rework the above function as follows:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
It seems reasonable, go on this way.
Regards, Stefano
Stefano,
I've just found that one of my boards fails with the above re-org. Strangely a board which has the same mem layout, mem width/size, CPU and nand does not fail.
If I make the following change:

On Tue, May 13, 2014 at 9:58 PM, Tim Harvey tharvey@gateworks.com wrote:
On Wed, May 7, 2014 at 2:29 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
On 06/05/2014 20:18, Tim Harvey wrote:
Stefano / York,
While preparing for a v3 patch series of my IMX6 SPL bootloader, I find that commit dec1861be90c948ea9fb771927d3d26a994d2e20 [1] breaks the above code because gd is now needed within setup_i2c.
I've always been a bit fuzzy on the order of the above calls so I dug through the code and I think I understand things better. Please correct any wrong assumptions I'm making below:
- assignment to gd should 'always' be first (before anything needs
it, so why not do it first)
- arch_cpu_init() should go next as this sets up very low level
CPU/SoC resources (in this case AIPS config and watchdog disable)
- board_early_init_f() should be next as that sets up any board-specific iomux
- any additional iomux necessary for SPL should go next (I take care
of i2c iomux and setup here)
- timer_init() next as you need a timer for UART and mxc i2c (for
delays and busy checks)
- preloader_console_init() next as we are now able to send something
over the UART (this gives me early debug for sdram config now too!)
- sdram setup goes next
- after sdram is setup, the bss can be cleared
- board_init_r - pass over to generic SPL code which will load/call
an image based on boot device
I think your analyses is correct.
So, if the above is correct, I should rework the above function as follows:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
It seems reasonable, go on this way.
Regards, Stefano
Stefano,
I've just found that one of my boards fails with the above re-org. Strangely a board which has the same mem layout, mem width/size, CPU and nand does not fail.
If I make the following change:
(sorry, accidentally fat fingered and sent instead of pasting). I'll continue:
--- a/board/gateworks/gw_ventana/gw_ventana_spl.c +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -380,9 +380,6 @@ void board_init_f(ulong dummy) */ memset((void *)gd, 0, sizeof(struct global_data));
- /* setup AIPS and disable watchdog */ - arch_cpu_init(); - /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); @@ -407,6 +404,9 @@ void board_init_f(ulong dummy) 16 << ventana_info.sdram_size, board_model);
+ /* setup AIPS and disable watchdog */ + arch_cpu_init(); + /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start);
Things start to work properly. I took a look at arch_cpu_init() and the call that really needs to be moved (or just duplicated here) is mxs_dma_init() to start APBH DMA. The failure mode of the one board is that apparently it hangs while loading u-boot.img from NAND (which of course uses mxs_nand and thus APBH DMA).
Anyone know what's going on here and why mxs_dma_init() needs to be called after MMDC setup, and before clearing the BSS? I don't like having magic placement of functions without understanding why.
Thanks,
Tim

On Tue, May 13, 2014 at 10:03 PM, Tim Harvey tharvey@gateworks.com wrote:
On Tue, May 13, 2014 at 9:58 PM, Tim Harvey tharvey@gateworks.com wrote:
On Wed, May 7, 2014 at 2:29 AM, Stefano Babic sbabic@denx.de wrote:
Hi Tim,
On 06/05/2014 20:18, Tim Harvey wrote:
Stefano / York,
While preparing for a v3 patch series of my IMX6 SPL bootloader, I find that commit dec1861be90c948ea9fb771927d3d26a994d2e20 [1] breaks the above code because gd is now needed within setup_i2c.
I've always been a bit fuzzy on the order of the above calls so I dug through the code and I think I understand things better. Please correct any wrong assumptions I'm making below:
- assignment to gd should 'always' be first (before anything needs
it, so why not do it first)
- arch_cpu_init() should go next as this sets up very low level
CPU/SoC resources (in this case AIPS config and watchdog disable)
- board_early_init_f() should be next as that sets up any board-specific iomux
- any additional iomux necessary for SPL should go next (I take care
of i2c iomux and setup here)
- timer_init() next as you need a timer for UART and mxc i2c (for
delays and busy checks)
- preloader_console_init() next as we are now able to send something
over the UART (this gives me early debug for sdram config now too!)
- sdram setup goes next
- after sdram is setup, the bss can be cleared
- board_init_r - pass over to generic SPL code which will load/call
an image based on boot device
I think your analyses is correct.
So, if the above is correct, I should rework the above function as follows:
void board_init_f(ulong dummy) { struct ventana_board_info ventana_info; int board_model;
/* Set global data pointer. */ gd = &gdata; /* setup AIPS and disable watchdog */ arch_cpu_init(); /* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux(); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* read/validate EEPROM info to determine board model and SDRAM cfg */ board_model = read_eeprom(I2C_GSC, &ventana_info); /* provide some some default: 32bit 128MB */ if (GW_UNKNOWN == board_model) { ventana_info.sdram_width = 2; ventana_info.sdram_size = 3; } /* configure MMDC for SDRAM width/size and per-model calibration */ spl_dram_init(8 << ventana_info.sdram_width, 16 << ventana_info.sdram_size, board_model); /* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start); /* load/boot image from boot device */ board_init_r(NULL, 0);
}
It seems reasonable, go on this way.
Regards, Stefano
Stefano,
I've just found that one of my boards fails with the above re-org. Strangely a board which has the same mem layout, mem width/size, CPU and nand does not fail.
If I make the following change:
(sorry, accidentally fat fingered and sent instead of pasting). I'll continue:
--- a/board/gateworks/gw_ventana/gw_ventana_spl.c +++ b/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -380,9 +380,6 @@ void board_init_f(ulong dummy) */ memset((void *)gd, 0, sizeof(struct global_data));
/* setup AIPS and disable watchdog */
arch_cpu_init();
/* iomux and setup of i2c */ board_early_init_f(); i2c_setup_iomux();
@@ -407,6 +404,9 @@ void board_init_f(ulong dummy) 16 << ventana_info.sdram_size, board_model);
/* setup AIPS and disable watchdog */
arch_cpu_init();
/* Clear the BSS. */ memset(__bss_start, 0, __bss_end - __bss_start);
Things start to work properly. I took a look at arch_cpu_init() and the call that really needs to be moved (or just duplicated here) is mxs_dma_init() to start APBH DMA. The failure mode of the one board is that apparently it hangs while loading u-boot.img from NAND (which of course uses mxs_nand and thus APBH DMA).
Anyone know what's going on here and why mxs_dma_init() needs to be called after MMDC setup, and before clearing the BSS? I don't like having magic placement of functions without understanding why.
Thanks,
Tim
I figured this one out - it has nothing to do with the order of calling arch_cpu_init() its that the MMDC isn't always 'ready' by the time the BSS is cleared and thus in my failure case the BSS isn't getting entirely cleared which causes the spl_image global var to not be cleared as expected and triggers an invalid codepath. I will update the mmdc config patch when I find the right solution.
Sorry for the noise.
Tim

Hi Tim,
On 15/05/2014 00:32, Tim Harvey wrote:
I figured this one out - it has nothing to do with the order of calling arch_cpu_init() its that the MMDC isn't always 'ready' by the time the BSS is cleared and thus in my failure case the BSS isn't getting entirely cleared which causes the spl_image global var to not be cleared as expected and triggers an invalid codepath. I will update the mmdc config patch when I find the right solution.
Thanks for the explanation ! I cannot guess why arch_cpu_init() should be called later. Nice you found the reason !
Sorry for the noise.
There was no noise ;-)
Best regards, Stefano
participants (11)
-
Eric Nelson
-
Igor Grinberg
-
Jeroen Hofstee
-
Masahiro Yamada
-
Nikita Kiryanov
-
Otavio Salvador
-
Scott Wood
-
Stefano Babic
-
Tapani Utriainen
-
Tim Harvey
-
York Sun