diff mbox

[U-Boot] ventana: Add Gateworks Ventana family support

Message ID 1390329660-2448-1-git-send-email-tharvey@gateworks.com
State Changes Requested
Delegated to: Stefano Babic
Headers show

Commit Message

Tim Harvey Jan. 21, 2014, 6:41 p.m. UTC
Gateworks Ventana is a product family based on the i.MX6.  This
patch adds support for all boards in the Ventana family. Where
possible, data from the boards EEPROM is used to determine various
details about the board at runtime.

Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
 board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg |   42 +
 board/gateworks/gw_ventana/800mhz_2x128mx16.cfg  |   42 +
 board/gateworks/gw_ventana/800mhz_4x128mx16.cfg  |   42 +
 board/gateworks/gw_ventana/Makefile              |   10 +
 board/gateworks/gw_ventana/README                |   49 +
 board/gateworks/gw_ventana/clocks.cfg            |   41 +
 board/gateworks/gw_ventana/ddr-setup.cfg         |   96 ++
 board/gateworks/gw_ventana/gw_ventana.c          | 1729 ++++++++++++++++++++++
 board/gateworks/gw_ventana/gw_ventana.cfg        |   42 +
 board/gateworks/gw_ventana/ventana_eeprom.h      |  107 ++
 boards.cfg                                       |    7 +-
 include/configs/gw_ventana.h                     |  409 +++++
 12 files changed, 2615 insertions(+), 1 deletion(-)
 create mode 100644 board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg
 create mode 100644 board/gateworks/gw_ventana/800mhz_2x128mx16.cfg
 create mode 100644 board/gateworks/gw_ventana/800mhz_4x128mx16.cfg
 create mode 100644 board/gateworks/gw_ventana/Makefile
 create mode 100644 board/gateworks/gw_ventana/README
 create mode 100644 board/gateworks/gw_ventana/clocks.cfg
 create mode 100644 board/gateworks/gw_ventana/ddr-setup.cfg
 create mode 100644 board/gateworks/gw_ventana/gw_ventana.c
 create mode 100644 board/gateworks/gw_ventana/gw_ventana.cfg
 create mode 100644 board/gateworks/gw_ventana/ventana_eeprom.h
 create mode 100644 include/configs/gw_ventana.h

Comments

Fabio Estevam Jan. 27, 2014, 11:57 a.m. UTC | #1
On Tue, Jan 21, 2014 at 4:41 PM, Tim Harvey <tharvey@gateworks.com> wrote:

> +static int setup_pmic_voltages(void)
> +{
> +       int ret;
> +       unsigned char value, rev_id = 0;
> +
> +       ret = i2c_set_bus_num(1);
> +       if (ret)
> +               return ret;
> +       if (!i2c_probe(0x8)) {
> +               if (i2c_read(0x8, 0, 1, &value, 1)) {
> +                       printf("Read device ID error!\n");
> +                       return -1;

Please use the PMIC API to read/write to the PMIC.

Regards,

Fabio Estevam
Stefano Babic Jan. 27, 2014, 2:39 p.m. UTC | #2
Hi Tim,

please run script/checkpatch on your patch before next submit. The tool
reports plenty of issues that must be solved for mainlining.

On 21/01/2014 19:41, Tim Harvey wrote:
> Gateworks Ventana is a product family based on the i.MX6.  This
> patch adds support for all boards in the Ventana family. Where
> possible, data from the boards EEPROM is used to determine various
> details about the board at runtime.
> 
> Signed-off-by: Tim Harvey <tharvey@gateworks.com>
> ---
>  board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg |   42 +
>  board/gateworks/gw_ventana/800mhz_2x128mx16.cfg  |   42 +
>  board/gateworks/gw_ventana/800mhz_4x128mx16.cfg  |   42 +

These three files to set up the DDR are *identical* to the files with
the same name in /board/boundary/nitrogen6x.

A such as duplication is not allowed. There should be a good reason to
have new files - for solidrun, different values are requested for DDR.

Please consider to refer to supplied files instead of copying.


> diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README
> new file mode 100644
> index 0000000..9de55ba
> --- /dev/null
> +++ b/board/gateworks/gw_ventana/README
> @@ -0,0 +1,49 @@
> +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
> +------------------------------
> +
> +The i.MX6 BOOT ROM expects some headers 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.

The behavior is quite different as we have currently in mainline. With
kobs-ng you flash u-boot.bin, while the result image for i.MXes in
mailine is u-boot.imx (u-boot.bin with imx header).

This behavior is also different to the roadmap we have discussed some
times ago for the i.MX6. We will move i.MX to use SPL, and the bad
blocks handling, not managed by the BOOT ROM, will be done inside SPL.

> +
> +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
> +with:
> +
> +kobs-ng init -v -x --search_exponent=1 u-boot.imx
> +
> +This information is taken from
> +
> +https://trac.gateworks.com/wiki/ventana%3Abuild_uboot

The link is broken - there is no permission with https, while http works.

> +
> +2. Build
> +--------
> +
> +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.

We will have another advantage with SPL, that is we can have a single
image working on different i.MX6 variants (Solo/Dual/Quad).

> +
> +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
> +
> +To build U-Boot for the MX6Q,1GB,NAND FLASH for example:
> +
> + make gwventanaq1g_config
> + make u-boot.imx

u-boot.imx should be the default target. But it seems weird you build
u-boot.imx and then discard it (or am I wrong ?) to take u-boot.bin.

> +
> diff --git a/board/gateworks/gw_ventana/clocks.cfg b/board/gateworks/gw_ventana/clocks.cfg
> new file mode 100644
> index 0000000..31790e7
> --- /dev/null
> +++ b/board/gateworks/gw_ventana/clocks.cfg
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (C) 2013 Gateworks Corporation
> + *

This is the only change in the file. The original file has a Boundary
Device Copyright. You cannot simply substitute the original Copyright
with your own.

clocks.cfg is then (apart some whitespaces) identical to clocks.cfg in
nitrogen. Please do not duplicate files.


> --- /dev/null
> +++ b/board/gateworks/gw_ventana/ddr-setup.cfg
> @@ -0,0 +1,96 @@
> +/*
> + * Copyright (C) 2013 Boundary Devices
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + *
> + * Device Configuration Data (DCD)
> + *
> + * Each entry must have the format:
> + * Addr-type           Address        Value
> + *
> + * where:
> + *      Addr-type register length (1,2 or 4 bytes)
> + *      Address   absolute address of the register
> + *      value     value to be stored in the register
> + */
> +

even ddr-setup.cfg is identical (but here Copyright is untouched).
It seems we do not need any special .cfg file for the board.

> diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c
> new file mode 100644
> index 0000000..418d1f8
> --- /dev/null
> +++ b/board/gateworks/gw_ventana/gw_ventana.c
> @@ -0,0 +1,1729 @@
> +/*
> + * Copyright (C) 2013 Gateworks Corporation
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/imx-regs.h>
> +#include <asm/arch/iomux.h>
> +#include <asm/arch/mx6-pins.h>
> +#include <asm/arch/crm_regs.h>
> +#include <asm/arch/mxc_hdmi.h>
> +#include <asm/arch/sys_proto.h>
> +#include <asm/errno.h>
> +#include <asm/gpio.h>
> +#include <asm/imx-common/iomux-v3.h>
> +#include <asm/imx-common/mxc_i2c.h>
> +#include <asm/imx-common/boot_mode.h>
> +#include <asm/imx-common/sata.h>
> +#include <linux/list.h>
> +#include <linux/ctype.h>
> +#include <linux/fb.h>
> +#include <mmc.h>
> +#include <fsl_esdhc.h>
> +#include <micrel.h>
> +#include <miiphy.h>
> +#include <netdev.h>
> +#include <ipu_pixfmt.h>
> +#include <i2c.h>
> +#include <fdt_support.h>
> +#include <jffs2/load_kernel.h>
> +#include <mtd_node.h>
> +#include <spi_flash.h>
> +#include <hwconfig.h>
> +#include <fuse.h>
> +
> +#include "ventana_eeprom.h"
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define UART_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |		\
> +	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED |		\
> +	PAD_CTL_DSE_40ohm   | PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
> +
> +#define USDHC_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE |		\
> +	PAD_CTL_PUS_47K_UP  | PAD_CTL_SPEED_LOW |		\
> +	PAD_CTL_DSE_80ohm   | PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
> +
> +#define ENET_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |		\
> +	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED	  |		\
> +	PAD_CTL_DSE_40ohm   | PAD_CTL_HYS)
> +
> +#define SPI_PAD_CTRL (PAD_CTL_HYS |				\
> +	PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_MED |		\
> +	PAD_CTL_DSE_40ohm     | PAD_CTL_SRE_FAST)
> +
> +#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 DIO_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |		\
> +	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED |		\
> +	PAD_CTL_DSE_34ohm | PAD_CTL_HYS | PAD_CTL_SRE_FAST)
> +
> +#define WEAK_PULLUP (PAD_CTL_PUS_100K_UP |			\
> +	PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS |	\
> +	PAD_CTL_SRE_SLOW)
> +
> +#define OUTPUT_40OHM (PAD_CTL_SPEED_MED|PAD_CTL_DSE_40ohm)
> +
> +/* UART1, RS485 */
> +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),
> +};
> +
> +/* UART2, 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),
> +};
> +
> +#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
> +
> +/* I2C1, GSC */
> +struct i2c_pads_info i2c_pad_info0 = {
> +	.scl = {
> +		.i2c_mode = MX6_PAD_EIM_D21__I2C1_SCL | PC,
> +		.gpio_mode = MX6_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,
> +		.gp = IMX_GPIO_NR(3, 28)
> +	}
> +};
> +
> +/* I2C2, PFUSE, PCIe Switch/Clock/Mezz */
> +struct i2c_pads_info i2c_pad_info1 = {
> +	.scl = {
> +		.i2c_mode = MX6_PAD_KEY_COL3__I2C2_SCL | PC,
> +		.gpio_mode = MX6_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,
> +		.gp = IMX_GPIO_NR(4, 13)
> +	}
> +};
> +
> +/* I2C3, Accel, Audio Codec, Video Decoder, Video Encoder, MIPI, LVDS, DIO */
> +struct i2c_pads_info i2c_pad_info2 = {
> +	.scl = {
> +		.i2c_mode = MX6_PAD_GPIO_3__I2C3_SCL | PC,
> +		.gpio_mode = MX6_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,
> +		.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 */
> +};
> +
> +/* 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),
> +	/* PHY nRST */
> +	MX6_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),
> +};
> +
> +#ifdef CONFIG_CMD_NAND
> +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));
> +
> +	/* config gpmi and bch clock to 100 MHz */
> +	clrsetbits_le32(&mxc_ccm->cs2cdr,
> +			MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK |
> +			MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK |
> +			MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK,
> +			MXC_CCM_CS2CDR_ENFC_CLK_PODF(0) |
> +			MXC_CCM_CS2CDR_ENFC_CLK_PRED(3) |
> +			MXC_CCM_CS2CDR_ENFC_CLK_SEL(3));
> +
> +	/* enable gpmi and bch clock gating */
> +	setbits_le32(&mxc_ccm->CCGR4,
> +		     MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK |
> +		     MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK |
> +		     MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK |
> +		     MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK |
> +		     MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_OFFSET);
> +
> +	/* enable apbh clock gating */
> +	setbits_le32(&mxc_ccm->CCGR0, MXC_CCM_CCGR0_APBHDMA_MASK);
> +}
> +#endif
> +
> +static void setup_iomux_enet(void)
> +{
> +	imx_iomux_v3_setup_multiple_pads(enet_pads, ARRAY_SIZE(enet_pads));
> +
> +	/* toggle PHY_RST# */
> +	gpio_direction_output(IMX_GPIO_NR(1, 30), 0);
> +	mdelay(2);
> +	gpio_set_value(IMX_GPIO_NR(1, 30), 1);
> +}
> +
> +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));
> +}
> +
> +#ifdef CONFIG_USB_EHCI_MX6
> +iomux_v3_cfg_t const usb_pads[] = {
> +	MX6_PAD_GPIO_1__USB_OTG_ID   | MUX_PAD_CTRL(WEAK_PULLUP),
> +	MX6_PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(WEAK_PULLUP),
> +	MX6_PAD_EIM_D22__GPIO3_IO22  | MUX_PAD_CTRL(OUTPUT_40OHM),
> +};
> +
> +int board_ehci_hcd_init(int port)
> +{
> +	/* Reset USB hub */
> +	imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT0__GPIO1_IO16 |
> +			MUX_PAD_CTRL(NO_PAD_CTRL));
> +	gpio_direction_output(IMX_GPIO_NR(1, 16), 0);
> +	mdelay(2);
> +	gpio_set_value(IMX_GPIO_NR(1, 16), 1);
> +
> +	return 0;
> +}
> +
> +int board_ehci_power(int port, int on)
> +{
> +	if (port)
> +		return 0;
> +	gpio_set_value(IMX_GPIO_NR(3, 22), on);
> +	return 0;
> +}
> +#endif /* CONFIG_USB_EHCI_MX6 */
> +
> +#ifdef CONFIG_FSL_ESDHC
> +struct fsl_esdhc_cfg usdhc_cfg[1] = {
> +	{USDHC3_BASE_ADDR},
> +};
> +
> +int board_mmc_getcd(struct mmc *mmc)
> +{
> +	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
> +	int ret = 0;
> +
> +	if (cfg->esdhc_base == USDHC3_BASE_ADDR) {
> +		/* Card Detect */
> +		gpio_direction_input(IMX_GPIO_NR(7, 0));
> +		ret = !gpio_get_value(IMX_GPIO_NR(7, 0));
> +	}
> +
> +	return ret;
> +}
> +
> +int board_mmc_init(bd_t *bis)
> +{
> +	s32 status = 0;
> +	u32 index = 0;
> +
> +	usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
> +	usdhc_cfg[0].max_bus_width = 4;
> +
> +	for (index = 0; index < CONFIG_SYS_FSL_USDHC_NUM; ++index) {
> +		switch (index) {
> +		case 0:

I know I am the first responsible for this code. But if
CONFIG_SYS_FSL_USDHC_NUM = 1 (and this is not easy changable without
modifying the board), why do we need a loop ?

> +/* Gateworks System Controller I2C access may NAK when busy - use

Wrong multiline comment. It should be:

/*
 * your comment
 * here
 */

> + * retries.
> + */
> +int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
> +{
> +	int retry = 3;
> +	int n = 0;
> +	int ret;
> +
> +	while (n++ < retry) {
> +		ret = i2c_read(chip, addr, alen, buf, len);
> +		if (!ret)
> +			break;
> +		printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
> +		       n, ret);
> +		if (ret != -ENODEV)
> +			break;
> +		mdelay(10);
> +	}

Whcih is the benefit of trying three times ?

> +int gsc_i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
> +{
> +	int retry = 3;
> +	int n = 0;
> +	int ret;
> +
> +	while (n++ < retry) {
> +		ret = i2c_write(chip, addr, alen, buf, len);
> +		if (!ret)
> +			break;
> +		printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
> +		       n, ret);
> +		if (ret != -ENODEV)
> +			break;
> +		mdelay(10);
> +	}
> +	mdelay(1);
> +	return ret;
> +}

Same here. If first time fails, something happens. It makes no sense to
try multiple times.

> +
> +/*
> + * For SPL boot some boards need i2c before SDRAM is initialized so force
> + * variables to live in SRAM
> + */

Agree - but then I will see SPL...

> +static struct ventana_board_info __attribute__((section(".data"))) ventana_info;

Can you explain why do you need this ?

> +
> +/* read ventana EEPROM and return structure or NULL on error

Multiline comment

> + * should be called once, the first time eeprom data is needed
> + */
> +static void
> +read_eeprom(void)
> +{

You have a I2C eprom. This is supported in U-Boot. Why do you not
set CONFIG_SYS_I2C_EEPROM_ADDR in your config file and use general code ?

It seems to me you can drop your own read/write_eeprom() function.

> +	int i;
> +	int chksum;
> +	struct ventana_board_info *info = &ventana_info;
> +	unsigned char *buf = (unsigned char *)&ventana_info;
> +	int n = 0;
> +
> +	memset(info, 0, sizeof(ventana_info));
> +
> +	/*  wait for bus and device exist - we will not boot w/o our EEPROM */
> +	while (1) {
> +		if (0 == i2c_set_bus_num(0) && 0 == i2c_probe(0x51))
> +			break;
> +		mdelay(1);
> +		n++;
> +	}
> +
> +	/* read eeprom config section */
> +	if (gsc_i2c_read(0x51, 0x00, 1, buf, sizeof(ventana_info))) {
> +		printf("EEPROM: Failed to read EEPROM\n");
> +		info->model[0] = 0;
> +		return;
> +	}
> +
> +	/* sanity checks */
> +	if (info->model[0] != 'G' || info->model[1] != 'W') {
> +		printf("EEPROM: Invalid Model in EEPROM\n");
> +		info->model[0] = 0;
> +		return;
> +	}

You can do your checks on the pyload after reading from the storage and
using common functions.

> +#ifdef CONFIG_CMD_GSC
> +int read_hwmon(const char *name, uint reg, uint size, uint low, uint high)
> +{
> +	unsigned char buf[3];
> +	uint ui;
> +	int ret;
> +
> +	printf("%-8s:", name);
> +	memset(buf, 0, sizeof(buf));
> +	if (gsc_i2c_read(0x29, reg, 1, buf, size)) {
> +		printf("fRD\n");
> +		ret = -1;
> +	} else {
> +		ret = 0;
> +		ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
> +		if (ui == 0xffffff) {
> +			printf("fVL");
> +		} else if (ui < low) {
> +			printf("%d fLO", ui);
> +			ret = -2;
> +		} else if (ui > high) {
> +			printf("%d fHI", ui);
> +			ret = -3;
> +		} else {
> +			printf("%d", ui);
> +		}
> +	}
> +	printf("\n");
> +
> +	return ret;
> +}

I need help - I have not understood. This functions prints only
something - return values is discarded when function is called. Buf is
filled, but can you better explain the purpose of the function.

> +
> +int do_gsc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +	struct ventana_board_info *info = &ventana_info;
> +
> +	i2c_set_bus_num(0);
> +	if ((strncasecmp((const char *)info->model, "GW51", 4) == 0)) {
> +		read_hwmon("Temp",     0x00, 2, 0, 9000);
> +		read_hwmon("VIN",      0x02, 3, 8000, 60000);
> +		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
> +		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
> +		read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
> +		read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
> +		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
> +		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
> +		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
> +		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
> +		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
> +	} else if ((strncasecmp((const char *)info->model, "GW52", 4) == 0)) {
> +		read_hwmon("Temp",     0x00, 2, 0, 9000);
> +		read_hwmon("VIN",      0x02, 3, 8000, 60000);
> +		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
> +		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
> +		read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
> +		read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
> +		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
> +		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
> +		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
> +		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
> +		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
> +		read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
> +	} else if ((strncasecmp((const char *)info->model, "GW53", 4) == 0)) {
> +		read_hwmon("Temp",     0x00, 2, 0, 9000);
> +		read_hwmon("VIN",      0x02, 3, 8000, 60000);
> +		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
> +		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
> +		read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
> +		read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
> +		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
> +		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
> +		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
> +		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
> +		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
> +		read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
> +	} else if ((strncasecmp((const char *)info->model, "GW54", 4) == 0)) {
> +		read_hwmon("Temp",     0x00, 2, 0, 9000);
> +		read_hwmon("VIN",      0x02, 3, 8000, 60000);
> +		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
> +		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
> +		read_hwmon("VDD_CORE", 0x0e, 3, 1375*0.9, 1375*1.1);
> +		read_hwmon("VDD_SOC",  0x11, 3, 1375*0.9, 1375*1.1);
> +		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
> +		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
> +		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
> +		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
> +		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
> +		read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
> +	}
> +	return 0;
> +}

I think we can do better. Most cases are duplicated. Please split into
common calls (for example, read_hwmon("Temp",     0x00, 2, 0, 9000) is
always called) and board-variations. The identification is done on a
single byte (GW51-GW54): you can use a more readable switch..case
instead of multiple strncmp()

> +
> +
> +/* get_mac from env string, with default
> + */
> +static void get_mac(char *envvar, unsigned char *def)
> +{
> +	char str[20];
> +	char *env = getenv(envvar);
> +
> +	if (!env) {
> +		sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
> +			def[0], def[1], def[2], def[3], def[4], def[5]);
> +		setenv(envvar, str);
> +	}
> +}

No idea why you need it. The FEC driver takes care of MAC address and
set the ethaddr variable. This seems to me wrong.

> +
> +#ifdef CONFIG_SERIAL_TAG
> +/* called when setting up ATAGS before booting kernel
> + * populate serialnum from the following (in order of priority):
> + *   serial# env var
> + *   eeprom
> + */
> +void get_board_serial(struct tag_serialnr *serialnr)
> +{
> +	char *serial = getenv("serial#");
> +
> +	if (serial) {
> +		serialnr->high = 0;
> +		serialnr->low = simple_strtoul(serial, NULL, 10);
> +	} else if (ventana_info.model[0]) {
> +		serialnr->high = 0;
> +		serialnr->low = ventana_info.serial;
> +	} else {
> +		serialnr->high = 0;
> +		serialnr->low = 0;
> +	}
> +}
> +#endif
> +
> +#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),
> +};
> +
> +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));
> +}
> +#endif
> +
> +int board_phy_config(struct phy_device *phydev)
> +{
> +	unsigned short val;
> +
> +	/* Marvel 88E1510 */
> +	if (phydev->phy_id == 0x1410dd1) {
> +		/* Errata 3.1 - PHY initialization */
> +		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214b);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0c28);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb233);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214d);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xcc0c);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fb);
> +		phy_write(phydev, MDIO_DEVAD_NONE,  7, 0xc00d);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
> +

This does not seem to me the best way to do. IMHO you should add support
for Marvel 88E1510 in drivers/net/phy/, maybe as Alaska phy.

In board_phy_config() should contain only board specific initialization
- an errata means that the same initialization is common to all boards
having this chip.

> +		/* LED configuration (See datasheet section 2.26.4)
> +		 * LED[0] (SPD:Amber) R16_3.3:0 to 0111: on-GbE link
> +		 * LED[1] (LNK:Green) R16_3.7:4 to 0001: on-link, blink-activity
> +		 */
> +		phy_write(phydev, MDIO_DEVAD_NONE, 22, 3);
> +		val = phy_read(phydev, MDIO_DEVAD_NONE, 16);
> +		val &= 0xff00;
> +		val |= 0x0017;
> +		phy_write(phydev, MDIO_DEVAD_NONE, 16, val);
> +		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
> +	}

This is also part of the phy driver.

> +int board_eth_init(bd_t *bis)
> +{
> +	int ret;
> +
> +	setup_iomux_enet();
> +
> +#ifdef CONFIG_FEC_MXC
> +	ret = cpu_eth_init(bis);
> +	if (ret)
> +		printf("FEC MXC: %s:failed\n", __func__);
> +#endif
> +
> +#ifdef CONFIG_MV_UDC
> +	/* For otg ethernet*/
> +	usb_eth_initialize(bis);
> +#endif
> +
> +	return 0;
> +}
> +
> +static void setup_board_gpio(const char *model)
> +{
> +	const char *s;
> +	char arg[10];
> +	size_t len;
> +	int i;
> +	enum {
> +		GW51xx,
> +		GW52xx,
> +		GW53xx,
> +		GW54xx,
> +		UNKNOWN,
> +	};
> +	struct dio_cfg {
> +		iomux_v3_cfg_t gpio_padmux;
> +		unsigned gpio_param;
> +		iomux_v3_cfg_t pwm_padmux;
> +		unsigned pwm_param;
> +	};
> +	int board_type = UNKNOWN;
> +	struct dio_cfg dio_cfg[] = {
> +		/* GW51xx */
> +		{ 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 },
> +
> +		/* GW52xx */
> +		{ 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 },
> +
> +		/* GW53xx */
> +		{ 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 },
> +
> +		/* GW54xx */
> +		{ 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 },
> +	};
> +
> +	if (strncasecmp(model, "GW51", 4) == 0) {
> +		board_type = GW51xx;
> +
> +		/* PANLEDG# (GRN off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
> +

Again, this is not straightforward and difficult to read. Use tables for
each board variation you want to add and split between common code and
specific code.

> +		/* PANLEDR# (RED off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
> +
> +		/* GPS_SHDN */
> +		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_2__GPIO1_IO02 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 2), 1);
> +
> +		/* Analog video codec power enable */
> +		imx_iomux_v3_setup_pad(MX6_PAD_CSI0_DATA_EN__GPIO5_IO20 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(5, 20), 1);
> +
> +		/* Expansion IO0 - PWREN# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
> +
> +		/* Expansion IO1 - IRQ# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_input(IMX_GPIO_NR(2, 18));
> +	} /* end GW51xx */
> +
> +	else if (strncasecmp(model, "GW52", 4) == 0) {
> +		board_type = GW52xx;
> +
> +		/* PANLEDG# (GRN off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
> +
> +		/* PANLEDR# (RED off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
> +
> +		/* MX6_LOCLED# (off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
> +
> +		/* GPS_SHDN */
> +		imx_iomux_v3_setup_pad(MX6_PAD_ENET_RXD0__GPIO1_IO27 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 27), 1);
> +
> +		/* Expansion IO0 - PWREN# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
> +
> +		/* Expansion IO1 - IRQ# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_input(IMX_GPIO_NR(2, 18));
> +
> +		/* MSATA Enable */
> +		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		if (is_cpu_type(MXC_CPU_MX6Q)) {
> +			gpio_direction_output(IMX_GPIO_NR(2, 8),
> +					      (hwconfig("msata")) ? 1 : 0);
> +			printf("MSATA: %s\n", (hwconfig("msata") ?
> +			       "enabled" : "disabled"));
> +		} else {
> +			gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
> +		}
> +
> +		/* USBOTG Select (PCISKT or FrontPanel) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_2__GPIO1_IO02 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 2), 0);
> +
> +		/* Analog video codec power enable */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
> +
> +		/* UART2_EN# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		printf("RS232: %s\n", (hwconfig("rs232")) ?
> +		       "enabled" : "disabled");
> +		gpio_direction_output(IMX_GPIO_NR(2, 11),
> +				      (hwconfig("rs232")) ? 0 : 1);
> +		/* TODO: flush UART RX FIFO after disable */
> +	} /* end GW52xx */
> +
> +	else if (strncasecmp(model, "GW53", 4) == 0) {
> +		board_type = GW53xx;
> +
> +		/* PANLEDG# (GRN off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
> +
> +		/* PANLEDR# (RED off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
> +
> +		/* MX6_LOCLED# (off) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
> +
> +		/* GPS_SHDN */
> +		imx_iomux_v3_setup_pad(MX6_PAD_ENET_RXD0__GPIO1_IO27 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 27), 1);
> +
> +		/* Expansion IO0 - PWREN# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
> +
> +		/* Expansion IO1 - IRQ# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_input(IMX_GPIO_NR(2, 18));
> +
> +		/* MSATA Enable */
> +		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		if (is_cpu_type(MXC_CPU_MX6Q)) {
> +			gpio_direction_output(IMX_GPIO_NR(2, 8),
> +					      (hwconfig("msata")) ? 1 : 0);
> +			printf("MSATA: %s\n", (hwconfig("msata") ?
> +			       "enabled" : "disabled"));
> +		} else {
> +			gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
> +		}
> +
> +		/* Analog video codec power enable */
> +		imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
> +
> +		/* UART2_EN# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		printf("RS232: %s\n", (hwconfig("rs232")) ?
> +		       "enabled" : "disabled");
> +		gpio_direction_output(IMX_GPIO_NR(2, 11),
> +				      (hwconfig("rs232")) ? 0 : 1);
> +		/* TODO: flush UART RX FIFO after disable */
> +	} /* end GW53xx */
> +
> +	else if (strncasecmp(model, "GW54", 4) == 0) {
> +		board_type = GW54xx;
> +		if (strncasecmp(model, "GW5400-A", 8) == 0) {
> +			/* PANLEDG# (GRN off) */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
> +
> +			/* PANLEDR# (RED off) */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL2__GPIO4_IO10 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 10), 1);
> +
> +			/* MX6_LOCLED# (off) */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
> +
> +			/* MIPI DIO */
> +			imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT3__GPIO1_IO21 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +
> +			/* RS485 Transmit Enable */
> +			imx_iomux_v3_setup_pad(MX6_PAD_EIM_D24__GPIO3_IO24 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(3, 24), 0);
> +
> +			/* Expansion IO0 - PWREN# */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 7), 0);
> +
> +			/* Expansion IO1 - IRQ# */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW1__GPIO4_IO09 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_input(IMX_GPIO_NR(4, 9));
> +		}
> +
> +		else if ((strncasecmp(model, "GW5400", 6) == 0) ||
> +			 (strncasecmp(model, "GW5410", 6) == 0)
> +		) {
> +			/* PANLEDG# (GRN off) */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
> +
> +			/* PANLEDR# (RED off) */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
> +
> +			/* MX6_LOCLED# (off) */
> +			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
> +
> +			/* RS485 Transmit Enable */
> +			imx_iomux_v3_setup_pad(MX6_PAD_SD3_DAT4__GPIO7_IO01 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(7, 1), 0);
> +
> +			/* Expansion IO0 - PWREN# */
> +			imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
> +
> +			/* Expansion IO1 - IRQ# */
> +			imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_input(IMX_GPIO_NR(2, 18));
> +
> +			/* MSATA Enable */
> +			imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			if (is_cpu_type(MXC_CPU_MX6Q)) {
> +				gpio_direction_output(IMX_GPIO_NR(2, 8),
> +						      (hwconfig("msata")) ?
> +						      1 : 0);
> +				printf("MSATA: %s\n", (hwconfig("msata") ?
> +				       "enabled" : "disabled"));
> +			} else {
> +				gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
> +			}
> +
> +			/* Analog video codec power enable */
> +			imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +			gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
> +		}
> +
> +		/* UART2_EN# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
> +					       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		printf("RS232: %s\n", (hwconfig("rs232")) ?
> +		       "enabled" : "disabled");
> +		gpio_direction_output(IMX_GPIO_NR(2, 11),
> +				      (hwconfig("rs232")) ? 0 : 1);
> +		/* TODO: flush UART RX FIFO after disable */
> +
> +		/* DIOI2C_DIS# */
> +		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_19__GPIO4_IO05 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(4,  5), 0);
> +	} /* end GW54xx */
> +
> +	/* Configure DIO pinmux/padctl registers
> +	 * see IMX6DQRM/IMX6SDLRM IOMUXC_SW_PAD_CTL_PAD_* register definitions
> +	 */
> +	if (board_type > UNKNOWN)
> +		return;
> +	for (i = 0; i < 4; i++) {
> +		struct dio_cfg *cfg = &dio_cfg[(4*board_type)+i];
> +		unsigned ctrl = DIO_PAD_CTRL;
> +
> +		sprintf(arg, "dio%d", i);
> +		if (hwconfig(arg)) {
> +			s = hwconfig_subarg(arg, "padctrl", &len);
> +			if (s)
> +				ctrl = simple_strtoul(s, NULL, 16) & 0x3ffff;
> +			if (hwconfig_subarg_cmp(arg, "mode", "gpio")) {
> +				printf("DIO%d:  GPIO%d_IO%02d (gpio-%d)\n", i,
> +				       (cfg->gpio_param/32)+1,
> +				       cfg->gpio_param%32,
> +				       cfg->gpio_param);
> +				imx_iomux_v3_setup_pad(cfg->gpio_padmux |
> +						       MUX_PAD_CTRL(ctrl));
> +				gpio_direction_input(cfg->gpio_param);
> +			} else if (hwconfig_subarg_cmp("dio2", "mode", "pwm") &&
> +				   cfg->pwm_padmux) {
> +				printf("DIO%d:  pwm%d\n", i, cfg->pwm_param);
> +				imx_iomux_v3_setup_pad(cfg->pwm_padmux |
> +						       MUX_PAD_CTRL(ctrl));
> +			}
> +		}
> +	}
> +}
> +
> +static int setup_pcie(void)
> +{
> +	struct ventana_board_info *info = &ventana_info;
> +
> +	if ((strncasecmp((const char *)info->model, "GW51", 4) == 0)) {
> +		/* assert PCI_RST#
> +		 * (will be released by OS when clock is valid) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_0__GPIO1_IO00 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 0), 0);
> +	} else if ((strncasecmp((const char *)info->model, "GW52", 4) == 0)) {
> +		/* assert PCI_RST#
> +		 * (will be released by OS when clock is valid) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
> +	} else if ((strncasecmp((const char *)info->model, "GW53", 4) == 0)) {
> +		/* assert PCI_RST#
> +		 * (will be released by OS when clock is valid) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
> +	} else if ((strncasecmp((const char *)info->model, "GW54", 4) == 0)) {
> +		/* PCICK_SSON: disable spread-spectrum clock */
> +		imx_iomux_v3_setup_pad(MX6_PAD_SD1_CLK__GPIO1_IO20 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 20), 0);
> +
> +		/* assert PCI_RST#
> +		 * (will be released by OS when clock is valid) */
> +		imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
> +				       MUX_PAD_CTRL(NO_PAD_CTRL));
> +		gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
> +	}
> +
> +	return 0;
> +}

Please take a look at Marek's later merged patches that add PCI-E
support for i.MX6 to U-Boot, and rebase on top of it. I can suggest to
use u-boot-imx as base for your patches, because patches are already merged.

Generally, I think you should change the behavior of selecting data on
depend of the board. Instead of checkig in each function which is the
board, you should add table containinig all required values, and choose
one of them in only one function.

> +
> +#if defined(CONFIG_VIDEO_IPUV3)
> +
> +static iomux_v3_cfg_t const backlight_pads[] = {
> +	/* Backlight on MIPI connector: J16 */
> +	MX6_PAD_SD2_CMD__GPIO1_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
> +
> +	/* Backlight CABEN on LVDS connector: J6 */
> +	MX6_PAD_SD2_CLK__GPIO1_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
> +};
> +
> +struct display_info_t {
> +	int	bus;
> +	int	addr;
> +	int	pixfmt;
> +	int	(*detect)(struct display_info_t const *dev);
> +	void	(*enable)(struct display_info_t const *dev);
> +	struct	fb_videomode mode;
> +};
> +
> +
> +static int detect_hdmi(struct display_info_t const *dev)
> +{
> +	struct hdmi_regs *hdmi  = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR;
> +	return readb(&hdmi->phy_stat0) & HDMI_PHY_HPD;
> +}
> +
> +static void do_enable_hdmi(struct display_info_t const *dev)
> +{
> +	imx_enable_hdmi_phy();
> +}
> +
> +static int detect_i2c(struct display_info_t const *dev)
> +{
> +	return ((0 == i2c_set_bus_num(dev->bus)) &&
> +		(0 == i2c_probe(dev->addr)));
> +}
> +
> +static void enable_lvds(struct display_info_t const *dev)
> +{
> +	struct iomuxc *iomux = (struct iomuxc *)
> +				IOMUXC_BASE_ADDR;
> +
> +	/* set CH0 data width to 24bit (IOMUXC_GPR2:5 0=18bit, 1=24bit) */
> +	u32 reg = readl(&iomux->gpr[2]);
> +	reg |= IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT;
> +	writel(reg, &iomux->gpr[2]);
> +
> +	/* Disable CABC:
> +	 * when enabled this feature sets backlight automatically according
> +	 * to content which may cause annoying unstable backlight issue
> +	 */
> +	gpio_direction_output(IMX_GPIO_NR(1, 10), 0);
> +
> +	/* Enable Backlight */
> +	imx_iomux_v3_setup_pad(MX6_PAD_SD1_CMD__GPIO1_IO18 |
> +			       MUX_PAD_CTRL(NO_PAD_CTRL));
> +	gpio_direction_output(IMX_GPIO_NR(1, 18), 1);
> +}
> +
> +static struct display_info_t const displays[] = {{
> +	/* HDMI Output */
> +	.bus	= -1,
> +	.addr	= 0,
> +	.pixfmt	= IPU_PIX_FMT_RGB24,
> +	.detect	= detect_hdmi,
> +	.enable	= do_enable_hdmi,
> +	.mode	= {
> +		.name           = "HDMI",
> +		.refresh        = 60,
> +		.xres           = 1024,
> +		.yres           = 768,
> +		.pixclock       = 15385,
> +		.left_margin    = 220,
> +		.right_margin   = 40,
> +		.upper_margin   = 21,
> +		.lower_margin   = 7,
> +		.hsync_len      = 60,
> +		.vsync_len      = 10,
> +		.sync           = FB_SYNC_EXT,
> +		.vmode          = FB_VMODE_NONINTERLACED
> +} }, {
> +	/* HannStar HSD100PXN1-A00 with egalx_ts controller
> +	 * (aka Freescale MXC-LVDS1 10" 1024x768 60Hz LCD touchscreen)
> +	 */
> +	.bus	= 2,
> +	.addr	= 0x4,
> +	.pixfmt	= IPU_PIX_FMT_LVDS666,
> +	.detect	= detect_i2c,
> +	.enable	= enable_lvds,
> +	.mode	= {
> +		.name           = "Hannstar-XGA",
> +		.refresh        = 60,
> +		.xres           = 1024,
> +		.yres           = 768,
> +		.pixclock       = 15385,
> +		.left_margin    = 220,
> +		.right_margin   = 40,
> +		.upper_margin   = 21,
> +		.lower_margin   = 7,
> +		.hsync_len      = 60,
> +		.vsync_len      = 10,
> +		.sync           = FB_SYNC_EXT,
> +		.vmode          = FB_VMODE_NONINTERLACED
> +} } };
> +
> +int board_video_skip(void)
> +{
> +	int i;
> +	int ret;
> +	char const *panel = getenv("panel");
> +	if (!panel) {
> +		for (i = 0; i < ARRAY_SIZE(displays); i++) {
> +			struct display_info_t const *dev = displays+i;
> +			if (dev->detect(dev)) {
> +				panel = dev->mode.name;
> +				printf("auto-detected panel %s\n", panel);
> +				break;
> +			}
> +		}
> +		if (!panel) {
> +			panel = displays[0].mode.name;
> +			i = 0;
> +			printf("No panel detected: default to %s\n", panel);
> +		}
> +	} else {
> +		for (i = 0; i < ARRAY_SIZE(displays); i++) {
> +			if (!strcmp(panel, displays[i].mode.name))
> +				break;
> +		}
> +	}
> +	if (i < ARRAY_SIZE(displays)) {
> +		ret = ipuv3_fb_init(&displays[i].mode, 0,
> +				    displays[i].pixfmt);
> +		if (!ret) {
> +			displays[i].enable(displays+i);
> +			printf("DISP:  %s (%ux%u)\n",
> +			       displays[i].mode.name,
> +			       displays[i].mode.xres,
> +			       displays[i].mode.yres);
> +		} else
> +			printf("LCD %s cannot be configured: %d\n",
> +			       displays[i].mode.name, ret);
> +	} else {
> +		printf("unsupported panel %s\n", panel);
> +		ret = -EINVAL;
> +	}
> +	return (0 != ret);
> +
}

Nak. This function is more or less copied from another board. There is
still a patch doing this and my suggestion is to factorize the part in
board_video_skip(), taht is not really strict bound to the board.

> +
> +static void setup_display(void)
> +{
> +	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
> +	struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
> +	int reg;
> +
> +	enable_ipu_clock();
> +	imx_setup_hdmi();
> +
> +	/* Turn on LDB0,IPU,IPU DI0 clocks */
> +	reg = readl(&mxc_ccm->CCGR3);
> +	reg |= MXC_CCM_CCGR3_LDB_DI0_MASK;
> +	writel(reg, &mxc_ccm->CCGR3);
> +
> +	/* set LDB0, LDB1 clk select to 011/011 */
> +	reg = readl(&mxc_ccm->cs2cdr);
> +	reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
> +		 |MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
> +	reg |= (3<<MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
> +	      |(3<<MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
> +	writel(reg, &mxc_ccm->cs2cdr);
> +
> +	reg = readl(&mxc_ccm->cscmr2);
> +	reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
> +	writel(reg, &mxc_ccm->cscmr2);
> +
> +	reg = readl(&mxc_ccm->chsccdr);
> +	reg |= (CHSCCDR_CLK_SEL_LDB_DI0
> +		<<MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
> +	writel(reg, &mxc_ccm->chsccdr);
> +
> +	reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
> +	     |IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
> +	     |IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
> +	     |IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
> +	     |IOMUXC_GPR2_DATA_WIDTH_CH1_18BIT
> +	     |IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
> +	     |IOMUXC_GPR2_DATA_WIDTH_CH0_18BIT
> +	     |IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
> +	     |IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
> +	writel(reg, &iomux->gpr[2]);
> +
> +	reg = readl(&iomux->gpr[3]);
> +	reg = (reg & ~IOMUXC_GPR3_LVDS0_MUX_CTL_MASK)
> +	    | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
> +	       <<IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
> +	writel(reg, &iomux->gpr[3]);
> +
> +	/* backlights off until needed */
> +	imx_iomux_v3_setup_multiple_pads(backlight_pads,
> +					 ARRAY_SIZE(backlight_pads));
> +	gpio_direction_input(IMX_GPIO_NR(1, 10)); /* LVDS */
> +	gpio_direction_input(IMX_GPIO_NR(1, 11)); /* MIPI */
> +}
> +#endif /* CONFIG_VIDEO_IPUV3 */
> +
> +static int setup_pmic_voltages(void)
> +{
> +	int ret;
> +	unsigned char value, rev_id = 0;
> +
> +	ret = i2c_set_bus_num(1);
> +	if (ret)
> +		return ret;
> +	if (!i2c_probe(0x8)) {

Nak. We have a generic PMIX framework. Please use it.

> +/*
> + * Board Support
> + */
> +
> +/*
> + * Do not overwrite the console
> + * Use always serial for U-Boot console
> + */
> +int overwrite_console(void)

This is not required, please drop it.

> +{
> +	return 1;
> +}
> +
> +
> +/*
> + * very early in the call chain - setup SoC peripherals
> + * (NB: Can not printf from here)
> + */
> +int board_early_init_f(void)
> +{
> +	setup_iomux_uart();
> +#ifdef CONFIG_MXC_SPI
> +	setup_spi();

 board_early_init_f() is called before relocation and malloc() is not
available. SPI uses malloc(), then you should move setup_spi to a later
point.

> +#endif
> +	gpio_direction_output(IMX_GPIO_NR(3, 22), 0); /* OTG power off */
> +
> +	/* Note this gets called again later,
> +	 * but needed in case i2c bus is stuck */
> +	timer_init();

timer_init() ? I think this is called by generic code.

> +	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 defined(CONFIG_VIDEO_IPUV3)
> +	setup_display();
> +#endif
> +
> +	return 0;
> +}
> +
> +#if defined(CONFIG_DISPLAY_BOARDINFO)
> +/* Identify board and display banner/info
> + */
> +#define SRC_SBMR1 0x020d8004  /* holds BOOT_CFG1-BOOT_CFG4 from eFuse/pins */
> +#define SRC_SBMR2 0x020d801c
> +#define SRC_GPR9  0x020d8040  /* holds copy of BOOT_CFG1-BOOT_CFG4 acted on */
> +#define SRC_GPR10 0x020d8044
> +

No access to internal register using absolute addresses. Use structures
in imx_regs.h. that is struct src->sbmrX

> +/* this reads boot_cfg efuse/pins - does not reflect what actually booted
> + */
> +void show_boot_mode(uint boot_cfg)
> +{
> +	switch ((boot_cfg & 0x000000ff) >> 4) {
> +	case 0x2:
> +		printf("SATA");
> +		break;
> +	case 0x3:
> +		printf("SPI NOR");
> +		break;
> +	case 0x4:
> +	case 0x5:
> +		/* BOOT_CFG2[3:4] is devno */
> +		printf(" SD%d", (boot_cfg & 0x00001800) >> 11);
> +		break;
> +	case 0x6:
> +	case 0x7:
> +		/* BOOT_CFG2[3:4] is devno */
> +		printf(" MMC%d", (boot_cfg & 0x00001800) >> 11);
> +		break;
> +	case 0x8 ... 0xf:
> +		printf("NAND");
> +		break;
> +	default:
> +		printf("Unknown");
> +		break;
> +	}
> +	printf(" 0x%08x\n", boot_cfg);
> +}
> +

This does not belog here. Please move this code in a separate patch and
make it available to all boards. Code should flow into
./arch/arm/imx-common. Please add a function getting an enumated value
as return value, not only a function that output the result.

Use puts() instead of printf() if you print a constant string.

Instead of:
		printf("NAND");

Use:
		puts("NAND");

> +
> +int checkboard(void)
> +{
> +	struct ventana_board_info *info = &ventana_info;
> +	uint src_sbmr2 = readl(SRC_SBMR2);
> +	uint src_gpr10 = readl(SRC_GPR10);
> +
> +	/* check for valid i2c busses - if one was 'stuck' it did not get
> +	 * initialized
> +	 */
> +	if (i2c_set_bus_num(0))
> +		printf("invalid /dev/i2c-0\n");

/dev has no meaning in U-Boot.

> +	if (i2c_set_bus_num(1))
> +		printf("invalid /dev/i2c-1\n");
> +	if (i2c_set_bus_num(2))
> +		printf("invalid /dev/i2c-2\n");
> +	read_eeprom();
> +	if (!(src_sbmr2 & 1<<4)) {
> +		/* can consider this 'manufacturing mode' if needed */
> +		printf("First boot - eFUSE not blown\n");
> +	}
> +
> +	printf("APP_IMAGE: %s\n", (src_gpr10 & 1<<30) ?
> +	       "Secondary" : "Primary");
> +	if (src_gpr10 & 1<<29)
> +		printf("NAND: bad blocks in application image\n");
> +
> +#if defined(CONFIG_ENV_IS_IN_SPI_FLASH)
> +	printf("Env: SPI FLASH\n");
> +#elif defined(CONFIG_ENV_IS_IN_MMC)
> +	printf("Env: MMC\n");
> +#elif defined(CONFIG_ENV_IS_IN_NAND)
> +	printf("Env: NAND FLASH\n");
> +#endif
> +
> +	/* SRC_SBMR1 reflects eFUSE/pin */
> +	printf("BOOT_CFG: ");
> +	show_boot_mode(readl(SRC_SBMR1));
> +	/* SRC_GPR9 reflects what was actually booted off of if not 0
> +	 * (ie if bmode was used) */
> +	if (readl(SRC_GPR9)) {
> +		printf("BMODE: ");
> +		show_boot_mode(readl(SRC_GPR9));
> +	}
> +	printf("\n");
> +	printf("Gateworks Corporation Copyright 2014\n");
> +	if (info->model[0]) {
> +		printf("Model: %s\n", info->model);
> +		printf("MFGDate: %02x-%02x-%02x%02x\n",
> +		       info->mfgdate[0], info->mfgdate[1],
> +		       info->mfgdate[2], info->mfgdate[3]);
> +		printf("Serial:%d\n", info->serial);
> +	} else {
> +		printf("Invalid EEPROM - board will not function fully\n");
> +	}
> +
> +	return 0;
> +}
> +#endif

General remak: you print a lot of stuff by booting. This can slow down
your boot process significantly adding several seconds to your start up,
before the kernel is loaded.

> +
> +/* Set gd->ram_size
> + */
> +int dram_init(void)
> +{
> +	struct ventana_board_info *info = &ventana_info;
> +
> +	gd->ram_size = ((ulong)CONFIG_DDR_MB * 1024 * 1024);
> +	if (info->model[0] && info->sdram_size > 0 && info->sdram_size < 9) {
> +		int i = info->sdram_size;
> +		gd->ram_size = 32*1024*1024;
> +		while (--i)
> +			gd->ram_size *= 2;
> +	}

Use get_ramsize to dynamically find the size of the installed RAM.

> +/* initialize periperhals
> + */
> +int board_init(void)
> +{
> +	int ret = 0;
> +	struct iomuxc_base_regs *const iomuxc_regs
> +		= (struct iomuxc_base_regs *)IOMUXC_BASE_ADDR;
> +
> +#ifdef CONFIG_CMD_NAND
> +	setup_gpmi_nand();
> +#endif
> +
> +	clrsetbits_le32(&iomuxc_regs->gpr[1],
> +			IOMUXC_GPR1_OTG_ID_MASK,
> +			IOMUXC_GPR1_OTG_ID_GPIO1);
> +
> +	imx_iomux_v3_setup_multiple_pads(usb_pads, ARRAY_SIZE(usb_pads));
> +
> +	/* address of linux boot parameters */
> +	gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
> +
> +#ifdef CONFIG_SYS_I2C_MXC
> +	ret = setup_pmic_voltages();
> +	if (ret)
> +		return -1;
> +#endif
> +
> +	setup_pcie();
> +
> +#ifdef CONFIG_CMD_SATA
> +	setup_sata();
> +#endif
> +
> +	if (!i2c_set_bus_num(0)) {
> +		unsigned char buf[4];
> +		if (!gsc_i2c_read(0x20, 14, 1, buf, 1)) {
> +			printf("GSC:   v%d", buf[0]);
> +			if (!gsc_i2c_read(0x20, 10, 1, buf, 4)) {
> +				/* show firmware revision and CRC */
> +				printf(" 0x%04x", buf[2] | buf[3]<<8);
> +				/* show status register */

I do not understand the code here. This should belong to checkboard().

> +/* late init
> + */
> +int misc_init_r(void)
> +{
> +	/* set env vars based on board model from EEPROM */
> +	if (ventana_info.model[0]) {
> +		char str[sizeof(ventana_info.model)];
> +		char fdt[sizeof(ventana_info.model)+20];
> +		char *p;
> +		int i;
> +		const char *prefix = "";
> +
> +		if (is_cpu_type(MXC_CPU_MX6Q))
> +			prefix = "imx6q";
> +		else if (is_cpu_type(MXC_CPU_MX6DL))
> +			prefix = "imx6dl";
> +
> +		memset(str, 0, sizeof(str));
> +		for (i = 0; i < (sizeof(ventana_info.model)-1) &&
> +		     ventana_info.model[i]; i++)
> +			str[i] = tolower(ventana_info.model[i]);
> +		if (!getenv("model"))
> +			setenv("model", str);
> +		if (!getenv("fdt_file")) {
> +			sprintf(fdt, "%s-%s.dtb", prefix, str);
> +			setenv("fdt_file", fdt);
> +		}
> +		p = strchr(str, '-');
> +		if (p) {
> +			*p++ = 0;
> +
> +			setenv("model_base", str);
> +			if (!getenv("fdt_file1")) {
> +				sprintf(fdt, "%s-%s.dtb", prefix, str);
> +				setenv("fdt_file1", fdt);
> +			}
> +			str[4] = 'x';
> +			str[5] = 'x';
> +			str[6] = 0;
> +			if (!getenv("fdt_file2")) {
> +				sprintf(fdt, "%s-%s.dtb", prefix, str);
> +				setenv("fdt_file2", fdt);
> +			}
> +		}
> +		get_mac("ethaddr", ventana_info.mac0);
> +		get_mac("eth1addr", ventana_info.mac1);
> +		sprintf(str, "%6d", ventana_info.serial);
> +		setenv("serial#", str);
> +		setup_board_gpio(getenv("model"));
> +	}
> +
> +	/* generate a random eth mac if no EEPROM (1st boot - mfg mode) */
> +	else {
> +		u32 ethaddr_low, ethaddr_high;
> +		char str[20];
> +
> +		/* use Device Unique ID bits 0-64 from eFUSE
> +		 * (OCOTP_CFG1/OCOTP_CFG2) */
> +		fuse_read(0, 1, &ethaddr_low);
> +		fuse_read(0, 2, &ethaddr_high);
> +
> +		/*
> +		 * setting the 2nd LSB in the most significant byte of
> +		 * the address makes it a locally administered ethernet
> +		 * address
> +		 */
> +		ethaddr_high &= 0xfeff;
> +		ethaddr_high |= 0x0200;
> +		sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
> +			ethaddr_high >> 8, ethaddr_high & 0xff,
> +			ethaddr_low >> 24, (ethaddr_low >> 16) & 0xff,
> +			(ethaddr_low >> 8) & 0xff, ethaddr_low & 0xff);
> +		printf("### Setting random MAC address = \"%s\"\n", str);
> +		setenv("ethaddr", str);
> +	}

Apart that this functionality should not be added to misc_init(), but to
the corresponding entry point (board_eth_init for example), I do not
think it is correct. If a random address can be generated, it should be
part of the FEC driver. The FEC already reads from fuses, that makes the
code here useless.

> +
> +#ifdef CONFIG_CMD_BMODE
> +	add_board_boot_modes(board_boot_modes);
> +#endif
> +
> +	/* disable GSC boot watchdog
> +	 *
> +	 *  The Gateworks System Controller implements a boot
> +	 *  watchdog (always enabled) to cover things like ERR006282 which can
> +	 *  lead to random boot failures.
> +	 */
> +	if (!i2c_set_bus_num(0)) {
> +		unsigned char val;
> +		if (!gsc_i2c_read(0x20, 1, 1, &val, 1)) {
> +			val |= 0x80;
> +			if (gsc_i2c_write(0x20, 1, 1, &val, 1))
> +				printf("Error: could not disable GSC Watchdog\n");
> +		} else {
> +			printf("Error: could not disable GSC Watchdog\n");
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
> +void ft_board_setup(void *blob, bd_t *bd)
> +{
> +	struct ventana_board_info *info = &ventana_info;
> +	struct node_info nodes[] = {
> +		{ "sst,w25q256",          MTD_DEV_TYPE_NOR, },  /* SPI flash */
> +		{ "fsl,imx6q-gpmi-nand",  MTD_DEV_TYPE_NAND, }, /* NAND flash */
> +	};
> +	const char *model = getenv("model");
> +
> +	if (getenv("fdt_noauto")) {
> +		printf("   Skiping ft_board_setup (fdt_noauto defined)\n");
> +		return;
> +	}
> +
> +	/* MTD partitions
> +	 * Update partition nodes using info from mtdparts env var
> +	 */
> +	printf("   Updating MTD partitions...\n");
> +	fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
> +
> +	if (!model) {
> +		printf("invalid board info: Leaving FDT fully enabled\n");
> +		return;
> +	}
> +	printf("   Adjusting FDT per EEPROM for %s...\n", model);
> +
> +	/* Note that fdt_fixup_ethernet is called in arm/lib/bootm before this
> +	 * which sets mac-address and local-mac-address properties of
> +	 * ethernet<n> aliases to ethaddr...eth<n>addr env
> +	 */
> +
> +	/* board serial number */
> +	fdt_setprop(blob, 0, "system-serial", getenv("serial#"),
> +		    strlen(getenv("serial#") + 1));
> +
> +	/* board (model contains model from device-tree) */
> +	fdt_setprop(blob, 0, "board", info->model,
> +		    strlen((const char *)info->model) + 1);
> +
> +	/* Peripheral Config */
> +	if (!info->config_eth0)
> +		fdt_del_node_and_alias(blob, "ethernet0");
> +	if (!info->config_eth1)
> +		fdt_del_node_and_alias(blob, "ethernet1");
> +	if (!info->config_hdmi_out)
> +		fdt_del_node_and_alias(blob, "hdmi_out");
> +	if (!info->config_sata)
> +		fdt_del_node_and_alias(blob, "ahci0");
> +	if (!info->config_pcie)
> +		fdt_del_node_and_alias(blob, "pcie");
> +	if (!info->config_ssi0)
> +		fdt_del_node_and_alias(blob, "ssi0");
> +	if (!info->config_ssi1)
> +		fdt_del_node_and_alias(blob, "ssi1");
> +	if (!info->config_lcd)
> +		fdt_del_node_and_alias(blob, "lcd0");
> +	if (!info->config_lvds0)
> +		fdt_del_node_and_alias(blob, "lvds0");
> +	if (!info->config_lvds1)
> +		fdt_del_node_and_alias(blob, "lvds1");
> +	if (!info->config_usb0)
> +		fdt_del_node_and_alias(blob, "usb0");
> +	if (!info->config_usb1)
> +		fdt_del_node_and_alias(blob, "usb1");
> +	if (!info->config_sd0)
> +		fdt_del_node_and_alias(blob, "usdhc0");
> +	if (!info->config_sd1)
> +		fdt_del_node_and_alias(blob, "usdhc1");
> +	if (!info->config_sd2)
> +		fdt_del_node_and_alias(blob, "usdhc2");
> +	if (!info->config_sd3)
> +		fdt_del_node_and_alias(blob, "usdhc3");
> +	if (!info->config_uart0)
> +		fdt_del_node_and_alias(blob, "serial0");
> +	if (!info->config_uart1)
> +		fdt_del_node_and_alias(blob, "serial1");
> +	if (!info->config_uart2)
> +		fdt_del_node_and_alias(blob, "serial2");
> +	if (!info->config_uart3)
> +		fdt_del_node_and_alias(blob, "serial3");
> +	if (!info->config_uart4)
> +		fdt_del_node_and_alias(blob, "serial4");
> +	if (!info->config_ipu0)
> +		fdt_del_node_and_alias(blob, "ipu0");
> +	if (!info->config_ipu1)
> +		fdt_del_node_and_alias(blob, "ipu1");
> +	if (!info->config_flexcan)
> +		fdt_del_node_and_alias(blob, "can0");
> +	if (!info->config_mipi_dsi)
> +		fdt_del_node_and_alias(blob, "mipi_dsi");
> +	if (!info->config_mipi_csi)
> +		fdt_del_node_and_alias(blob, "mipi_csi");
> +	if (!info->config_tzasc0)
> +		fdt_del_node_and_alias(blob, "tzasc0");
> +	if (!info->config_tzasc1)
> +		fdt_del_node_and_alias(blob, "tzasc1");
> +	if (!info->config_i2c0)
> +		fdt_del_node_and_alias(blob, "i2c0");
> +	if (!info->config_i2c1)
> +		fdt_del_node_and_alias(blob, "i2c1");
> +	if (!info->config_i2c2)
> +		fdt_del_node_and_alias(blob, "i2c2");
> +	if (!info->config_vpu)
> +		fdt_del_node_and_alias(blob, "vpu");
> +	if (!info->config_csi0)
> +		fdt_del_node_and_alias(blob, "csi0");
> +	if (!info->config_csi1)
> +		fdt_del_node_and_alias(blob, "csi1");
> +	if (!info->config_caam)
> +		fdt_del_node_and_alias(blob, "caam");
> +	if (!info->config_espci0)
> +		fdt_del_node_and_alias(blob, "spi0");
> +	if (!info->config_espci1)
> +		fdt_del_node_and_alias(blob, "spi1");
> +	if (!info->config_espci2)
> +		fdt_del_node_and_alias(blob, "spi2");
> +	if (!info->config_espci3)
> +		fdt_del_node_and_alias(blob, "spi3");
> +	if (!info->config_espci4)
> +		fdt_del_node_and_alias(blob, "spi4");
> +	if (!info->config_espci5)
> +		fdt_del_node_and_alias(blob, "spi5");
> +	if (!info->config_hdmi_in)
> +		fdt_del_node_and_alias(blob, "hdmi_in");
> +	if (!info->config_vid_out)
> +		fdt_del_node_and_alias(blob, "cvbs_out");
> +	if (!info->config_vid_in)
> +		fdt_del_node_and_alias(blob, "cvbs_in");
> +	if (!info->config_nand)
> +		fdt_del_node_and_alias(blob, "nand");
> +	if (!info->config_gps)
> +		fdt_del_node_and_alias(blob, "pps");

I find the way quite singular. It seems you have a full-blown .dts file
and you want to drop the features that you do not find in eeprom. A more
conventional way is to have a simpler or not fully configured dts and
add only the feature you want.

dts has the keyword "disabled", that let you enable or disable a
specific feature. Maybe you could exchange the "status" field in dts
instead of adding/dropping nodes.

> +}
> +#endif /* defined(CONFIG_OF_FLAT_TREE) && defined(CONFIG_OF_BOARD_SETUP) */
> +
> diff --git a/board/gateworks/gw_ventana/gw_ventana.cfg b/board/gateworks/gw_ventana/gw_ventana.cfg
> new file mode 100644
> index 0000000..4e07528
> --- /dev/null
> +++ b/board/gateworks/gw_ventana/gw_ventana.cfg
> @@ -0,0 +1,42 @@
> +/*
> + * Copyright (C) 2013 Gateworks Corporation
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
> + * Refer doc/README.imximage for more details about how-to configure
> + * and create imximage boot image
> + *
> + * The syntax is taken as close as possible with the kwbimage
> + */
> +
> +/* image version */
> +IMAGE_VERSION 2
> +
> +/*
> + * Boot Device : one of
> + * spi, sd, nand, sata
> + */
> +#ifdef CONFIG_SPI_FLASH
> +BOOT_FROM      spi
> +#else
> +BOOT_FROM      nand
> +#endif

Do you boot also from SPI ?

> +
> +#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 "ddr-setup.cfg"
> +#if defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 1024
> +  #include "1066mhz_4x128mx16.cfg"
> +#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 1024
> +  #include "800mhz_4x128mx16.cfg"
> +#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 512
> +  #include "800mhz_2x128mx16.cfg"
> +#else
> +  #error "Unsupported CPU/Memory configuration"
> +#endif
> +#include "clocks.cfg"
> diff --git a/board/gateworks/gw_ventana/ventana_eeprom.h b/board/gateworks/gw_ventana/ventana_eeprom.h
> new file mode 100644
> index 0000000..ea6524a
> --- /dev/null
> +++ b/board/gateworks/gw_ventana/ventana_eeprom.h
> @@ -0,0 +1,107 @@
> +/*
> + * ventana_eeprom.h - Gateworks Ventana EEPROM Configuration
> + * v1.00
> + */
> +#ifndef _VENTANA_EEPROM_
> +#define _VENTANA_EEPROM_
> +
> +struct ventana_board_info {
> +	u8 mac0[6];          /* 0x00: MAC1 */
> +	u8 mac1[6];          /* 0x06: MAC2 */
> +	u8 res0[12];         /* 0x0C: reserved */
> +	u32 serial;          /* 0x18: Serial Number (read only) */
> +	u8 res1[4];          /* 0x1C: reserved */
> +	u8 mfgdate[4];       /* 0x20: MFG date (read only) */
> +	u8 res2[7];          /* 0x24 */
> +	/* sdram config */
> +	u8 sdram_size;       /* 0x2B: enum (512,1024,2048) MB */
> +	u8 sdram_speed;      /* 0x2C: enum (100,133,166,200,267,333,400) MHz */
> +	u8 sdram_width;      /* 0x2D: enum (32,64) bit */
> +	/* cpu config */
> +	u8 cpu_speed;        /* 0x2E: enum (800,1000,1200) MHz */
> +	u8 cpu_type;         /* 0x2F: enum (imx6q,imx6d,imx6dl,imx6s) */
> +	u8 model[16];        /* 0x30: model string */
> +	/* FLASH config */
> +	u8 nand_flash_size;  /* 0x40: enum (4,8,16,32,64,128) MB */
> +	u8 spi_flash_size;   /* 0x41: enum (4,8,16,32,64,128) MB */
> +
> +	/* Config1: SoC Peripherals */
> +	u8 config_eth0:1;    /* 0: 0x42 */
> +	u8 config_eth1:1;    /* 1 */
> +	u8 config_hdmi_out:1;/* 2 */
> +	u8 config_sata:1;    /* 3 */
> +	u8 config_pcie:1;    /* 4 */
> +	u8 config_ssi0:1;    /* 5 */
> +	u8 config_ssi1:1;    /* 6 */
> +	u8 config_lcd:1;     /* 7 */

Generally, using bitwise fields is deprecated in favour of using maks.
This because there is no conventions how the compiler should assign (MSB
or LSB) the single bits.

> +
> +	u8 config_lvds0:1;   /* 0: 0x43 */
> +	u8 config_lvds1:1;   /* 1 */
> +	u8 config_usb0:1;    /* 2 (USB EHCI) */
> +	u8 config_usb1:1;    /* 3 (USB OTG) */
> +	u8 config_sd0:1;     /* 4 */
> +	u8 config_sd1:1;     /* 5 */
> +	u8 config_sd2:1;     /* 6 */
> +	u8 config_sd3:1;     /* 7 */
> +
> +	u8 config_uart0:1;   /* 0: 0x44 */
> +	u8 config_uart1:1;   /* 1 */
> +	u8 config_uart2:1;   /* 2 */
> +	u8 config_uart3:1;   /* 3 */
> +	u8 config_uart4:1;   /* 4 */
> +	u8 config_ipu0:1;    /* 5 */
> +	u8 config_ipu1:1;    /* 6 */
> +	u8 config_flexcan:1; /* 7 */
> +
> +	u8 config_mipi_dsi:1;/* 0: 0x45 */
> +	u8 config_mipi_csi:1;/* 1 */
> +	u8 config_tzasc0:1;  /* 2 */
> +	u8 config_tzasc1:1;  /* 3 */
> +	u8 config_i2c0:1;    /* 4 */
> +	u8 config_i2c1:1;    /* 5 */
> +	u8 config_i2c2:1;    /* 6 */
> +	u8 config_vpu:1;     /* 7 */
> +
> +	u8 config_csi0:1;    /* 0: 0x46 */
> +	u8 config_csi1:1;    /* 1 */
> +	u8 config_caam:1;    /* 2 */
> +	u8 config_mezz:1;    /* 3 */
> +	u8 config_res1:1;    /* 4 */
> +	u8 config_res2:1;    /* 5 */
> +	u8 config_res3:1;    /* 6 */
> +	u8 config_res4:1;    /* 7 */
> +
> +	u8 config_espci0:1;  /* 0: 0x47 */
> +	u8 config_espci1:1;  /* 1 */
> +	u8 config_espci2:1;  /* 2 */
> +	u8 config_espci3:1;  /* 3 */
> +	u8 config_espci4:1;  /* 4 */
> +	u8 config_espci5:1;  /* 5 */
> +	u8 config_res5:1;    /* 6 */
> +	u8 config_res6:1;    /* 7 */
> +
> +	/* Config2: Other Peripherals */
> +	u8 config_gps:1;     /* 0: 0x48 */
> +	u8 config_spifl0:1;  /* 1 */
> +	u8 config_spifl1:1;  /* 2 */
> +	u8 config_gspbatt:1; /* 3 */
> +	u8 config_hdmi_in:1; /* 4 */
> +	u8 config_vid_out:1; /* 5 */
> +	u8 config_vid_in:1;  /* 6 */
> +	u8 config_nand:1;    /* 7 */
> +
> +	u8 config_res8:1;    /* 0: 0x49 */
> +	u8 config_res9:1;    /* 1 */
> +	u8 config_res10:1;   /* 2 */
> +	u8 config_res11:1;   /* 3 */
> +	u8 config_res12:1;   /* 4 */
> +	u8 config_res13:1;   /* 5 */
> +	u8 config_res14:1;   /* 6 */
> +	u8 config_res15:1;   /* 7 */
> +
> +	u8 res3[4];          /* 0x4A */
> +
> +	u8 chksum[2];        /* 0x4E */
> +};
> +
> +#endif
> diff --git a/boards.cfg b/boards.cfg
> index a8336cc..7784b3a 100644
> --- a/boards.cfg
> +++ b/boards.cfg
> @@ -295,6 +295,7 @@ Active  arm         armv7          mx6         -               udoo		   udoo_qua
>  Active  arm         armv7          mx6         -               wandboard           wandboard_dl                         wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024                                                  Fabio Estevam <fabio.estevam@freescale.com>
>  Active  arm         armv7          mx6         -               wandboard           wandboard_quad                       wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q2g.cfg,MX6Q,DDR_MB=2048                                                  Fabio Estevam <fabio.estevam@freescale.com>
>  Active  arm         armv7          mx6         -               wandboard           wandboard_solo                       wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6s.cfg,MX6S,DDR_MB=512                                                     Fabio Estevam <fabio.estevam@freescale.com>
> +Active  arm         armv7          mx6         barco           titanium            titanium                             titanium:IMX_CONFIG=board/barco/titanium/imximage.cfg                                                                         Stefan Roese <sr@denx.de>

Why do you touch the titanium ?

>  Active  arm         armv7          mx6         boundary        nitrogen6x          mx6qsabrelite                        nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q.cfg,MX6Q,DDR_MB=1024,SABRELITE                                         Eric Nelson <eric.nelson@boundarydevices.com>
>  Active  arm         armv7          mx6         boundary        nitrogen6x          nitrogen6dl                          nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024                                                 Eric Nelson <eric.nelson@boundarydevices.com>
>  Active  arm         armv7          mx6         boundary        nitrogen6x          nitrogen6dl2g                        nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl2g.cfg,MX6DL,DDR_MB=2048                                               Eric Nelson <eric.nelson@boundarydevices.com>
> @@ -308,7 +309,11 @@ 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         barco           titanium            titanium                             titanium:IMX_CONFIG=board/barco/titanium/imximage.cfg                                                                         Stefan Roese <sr@denx.de>
> +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>

Please let the list sorted.

Best regards,
Stefano Babic
Tim Harvey Jan. 27, 2014, 5:53 p.m. UTC | #3
On Mon, Jan 27, 2014 at 3:57 AM, Fabio Estevam <festevam@gmail.com> wrote:
> On Tue, Jan 21, 2014 at 4:41 PM, Tim Harvey <tharvey@gateworks.com> wrote:
>
>> +static int setup_pmic_voltages(void)
>> +{
>> +       int ret;
>> +       unsigned char value, rev_id = 0;
>> +
>> +       ret = i2c_set_bus_num(1);
>> +       if (ret)
>> +               return ret;
>> +       if (!i2c_probe(0x8)) {
>> +               if (i2c_read(0x8, 0, 1, &value, 1)) {
>> +                       printf("Read device ID error!\n");
>> +                       return -1;
>
> Please use the PMIC API to read/write to the PMIC.

Fabio,

Thanks for the review!  I see include/power/pmic.h and will take a look.

Tim

>
> Regards,
>
> Fabio Estevam
Tim Harvey Jan. 27, 2014, 11:36 p.m. UTC | #4
On Mon, Jan 27, 2014 at 6:39 AM, Stefano Babic <sbabic@denx.de> wrote:
> Hi Tim,

Hi Stefano - thanks for the review!

>
> please run script/checkpatch on your patch before next submit. The tool
> reports plenty of issues that must be solved for mainlining.
>

It looks like I missed some >80 char formatting issues regarding the
env vars in the config file.  I'll fix those up.

> On 21/01/2014 19:41, Tim Harvey wrote:
>> Gateworks Ventana is a product family based on the i.MX6.  This
>> patch adds support for all boards in the Ventana family. Where
>> possible, data from the boards EEPROM is used to determine various
>> details about the board at runtime.
>>
>> Signed-off-by: Tim Harvey <tharvey@gateworks.com>
>> ---
>>  board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg |   42 +
>>  board/gateworks/gw_ventana/800mhz_2x128mx16.cfg  |   42 +
>>  board/gateworks/gw_ventana/800mhz_4x128mx16.cfg  |   42 +
>
> These three files to set up the DDR are *identical* to the files with
> the same name in /board/boundary/nitrogen6x.
>
> A such as duplication is not allowed. There should be a good reason to
> have new files - for solidrun, different values are requested for DDR.
>
> Please consider to refer to supplied files instead of copying.

I will include the ddr config files from boundary with a
../../boundary/... where they do not differ.  The clocks.cfg does
differ (see below) but I liked the way Boundary broke these files out
do want to re-use as much as possible.

>
>
>> diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README
>> new file mode 100644
>> index 0000000..9de55ba
>> --- /dev/null
>> +++ b/board/gateworks/gw_ventana/README
>> @@ -0,0 +1,49 @@
>> +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
>> +------------------------------
>> +
>> +The i.MX6 BOOT ROM expects some headers 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.
>
> The behavior is quite different as we have currently in mainline. With
> kobs-ng you flash u-boot.bin, while the result image for i.MXes in
> mailine is u-boot.imx (u-boot.bin with imx header).

I'm not familiar with the IMX family other than IMX6 but for IMX6
kobs-ng does use u-boot.imx and not u-boot.bin.  kobs needs the
headers which are not part of u-boot.bin.  Are you sure you are not
mistaken here?  Can you point me to some references?

>
> This behavior is also different to the roadmap we have discussed some
> times ago for the i.MX6. We will move i.MX to use SPL, and the bad
> blocks handling, not managed by the BOOT ROM, will be done inside SPL.

Yes - I would also like to an SPL bootloader, but have not quite
gotten that working yet for NAND.  I felt it was a good start to get
my current patchset mainlined as a starting point.

Regardless of what is loading the next level (u-boot.bin) the initial
flashing of NAND is still currently handled only by kobs-ng so I'm not
sure how this differs in this respect.  I plan to look at adding the
functionality of kobs-ng to u-boot at some point.

>
>> +
>> +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
>> +with:
>> +
>> +kobs-ng init -v -x --search_exponent=1 u-boot.imx
>> +
>> +This information is taken from
>> +
>> +https://trac.gateworks.com/wiki/ventana%3Abuild_uboot
>
> The link is broken - there is no permission with https, while http works.

Thanks for catching this.  The correct link is
http://trac.gateworks.com/wiki/ventana/bootloader#BuildingfromSource
and I will fix it in the next patch version.

>
>> +
>> +2. Build
>> +--------
>> +
>> +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.
>
> We will have another advantage with SPL, that is we can have a single
> image working on different i.MX6 variants (Solo/Dual/Quad).

agreed.

I really wanted to get to SPL before posting but felt I have a good
starting point equivalent with the other IMX6 boards currently in
mainline.  For SPL I need nand and i2c support (as we use i2c to
access the EEPROM which contains details about DDR configuration) and
currently both of those are creating some dependency issues that keep
the SPL from building for me.  I haven't had time to dig into that
yet.

>
>> +
>> +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
>> +
>> +To build U-Boot for the MX6Q,1GB,NAND FLASH for example:
>> +
>> + make gwventanaq1g_config
>> + make u-boot.imx
>
> u-boot.imx should be the default target. But it seems weird you build
> u-boot.imx and then discard it (or am I wrong ?) to take u-boot.bin.

u-boot.imx is the default target.  We don't discard it.  I will change
the instructions to just 'make gwventanaq1g_config; make' to avoid
confusion.

>
>> +
>> diff --git a/board/gateworks/gw_ventana/clocks.cfg b/board/gateworks/gw_ventana/clocks.cfg
>> new file mode 100644
>> index 0000000..31790e7
>> --- /dev/null
>> +++ b/board/gateworks/gw_ventana/clocks.cfg
>> @@ -0,0 +1,41 @@
>> +/*
>> + * Copyright (C) 2013 Gateworks Corporation
>> + *
>
> This is the only change in the file. The original file has a Boundary
> Device Copyright. You cannot simply substitute the original Copyright
> with your own.
>
> clocks.cfg is then (apart some whitespaces) identical to clocks.cfg in
> nitrogen. Please do not duplicate files.

I agree that the original copyright should be there and I'll add it,
but there is an important difference between the two so I cannot use
the original.  The Gateworks board uses NAND flash thus the CCM_CCGR4
register differs by a few bits.

- DATA 4, CCM_CCGR4, 0x00FFF300
+ DATA 4, CCM_CCGR4, 0xFFFFF300 /* enable NAND/GPMI/BCH clocks */


>
>
>> --- /dev/null
>> +++ b/board/gateworks/gw_ventana/ddr-setup.cfg
>> @@ -0,0 +1,96 @@
>> +/*
>> + * Copyright (C) 2013 Boundary Devices
>> + *
>> + * SPDX-License-Identifier:  GPL-2.0+
>> + *
>> + * Device Configuration Data (DCD)
>> + *
>> + * Each entry must have the format:
>> + * Addr-type           Address        Value
>> + *
>> + * where:
>> + *      Addr-type register length (1,2 or 4 bytes)
>> + *      Address   absolute address of the register
>> + *      value     value to be stored in the register
>> + */
>> +
>
> even ddr-setup.cfg is identical (but here Copyright is untouched).
> It seems we do not need any special .cfg file for the board.

just clocks.cfg at this point must differ.

>
<snip>
>> +
>> +int board_mmc_init(bd_t *bis)
>> +{
>> +     s32 status = 0;
>> +     u32 index = 0;
>> +
>> +     usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
>> +     usdhc_cfg[0].max_bus_width = 4;
>> +
>> +     for (index = 0; index < CONFIG_SYS_FSL_USDHC_NUM; ++index) {
>> +             switch (index) {
>> +             case 0:
>
> I know I am the first responsible for this code. But if
> CONFIG_SYS_FSL_USDHC_NUM = 1 (and this is not easy changable without
> modifying the board), why do we need a loop ?

Agreed - a loop is silly here, I'll remove it.

>
>> +/* Gateworks System Controller I2C access may NAK when busy - use
>
> Wrong multiline comment. It should be:
>
> /*
>  * your comment
>  * here
>  */

will fix thanks.  Someone else mentioned that to me and I have not
been able to find a style guide for multi-line comments.  Looks like
opening and closing should contain no text.

>
>> + * retries.
>> + */
>> +int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
>> +{
>> +     int retry = 3;
>> +     int n = 0;
>> +     int ret;
>> +
>> +     while (n++ < retry) {
>> +             ret = i2c_read(chip, addr, alen, buf, len);
>> +             if (!ret)
>> +                     break;
>> +             printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
>> +                    n, ret);
>> +             if (ret != -ENODEV)
>> +                     break;
>> +             mdelay(10);
>> +     }
>
> Whcih is the benefit of trying three times ?

it provides a little more redundancy than 2 times, and a little less than 4 ;)

Our GSC can occasionally be 'busy' and NAK (every 1Hz it does some
internal processing).  As there are several places where I perform an
i2c transaction to one of the GSC's slave devices (it emulates several
i2c devices) I wanted to consolidate where I had retry logic.  There
is nothing magic about 3 tries necessarily but I have found that with
the speed of the SoC we never fail more than 2 successive reads due to
the periodic loading of the GSC.

If you want more info on the GSC you can read about it here:
http://trac.gateworks.com/wiki/gsc

>
>> +int gsc_i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
>> +{
>> +     int retry = 3;
>> +     int n = 0;
>> +     int ret;
>> +
>> +     while (n++ < retry) {
>> +             ret = i2c_write(chip, addr, alen, buf, len);
>> +             if (!ret)
>> +                     break;
>> +             printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
>> +                    n, ret);
>> +             if (ret != -ENODEV)
>> +                     break;
>> +             mdelay(10);
>> +     }
>> +     mdelay(1);
>> +     return ret;
>> +}
>
> Same here. If first time fails, something happens. It makes no sense to
> try multiple times.

in our case I feel it does - see above.

>
>> +
>> +/*
>> + * For SPL boot some boards need i2c before SDRAM is initialized so force
>> + * variables to live in SRAM
>> + */
>
> Agree - but then I will see SPL...
>
>> +static struct ventana_board_info __attribute__((section(".data"))) ventana_info;
>
> Can you explain why do you need this ?

This was in preparation for SPL.  I'm not clear if the struct needs
any special attributes at this time to be available to all the
functions that use it.  Because currently the BOOTROM sets up DDR I'm
thinking perhaps not, but I seem to recall before I added the
attribute I ran into some issues.

>
>> +
>> +/* read ventana EEPROM and return structure or NULL on error
>
> Multiline comment

ack

>
>> + * should be called once, the first time eeprom data is needed
>> + */
>> +static void
>> +read_eeprom(void)
>> +{
>
> You have a I2C eprom. This is supported in U-Boot. Why do you not
> set CONFIG_SYS_I2C_EEPROM_ADDR in your config file and use general code ?
>
> It seems to me you can drop your own read/write_eeprom() function.

I considered this before (using common/cmd_eeprom.c), but the fact
that I want to be able to handle retries on NAK's would keep me from
using a generic read_eeprom feature.  Also, that common support only
just replaces my gsc_i2c_read function - inside read_eeprom I verify
checksum and some other sanity checks.  Grepping for
CONFIG_SYS_I2C_EEPROM_ADDR there are a lot of boards that implement
their own read_eeprom functionality for one reason or another.

>
>> +     int i;
>> +     int chksum;
>> +     struct ventana_board_info *info = &ventana_info;
>> +     unsigned char *buf = (unsigned char *)&ventana_info;
>> +     int n = 0;
>> +
>> +     memset(info, 0, sizeof(ventana_info));
>> +
>> +     /*  wait for bus and device exist - we will not boot w/o our EEPROM */
>> +     while (1) {
>> +             if (0 == i2c_set_bus_num(0) && 0 == i2c_probe(0x51))
>> +                     break;
>> +             mdelay(1);
>> +             n++;
>> +     }
>> +
>> +     /* read eeprom config section */
>> +     if (gsc_i2c_read(0x51, 0x00, 1, buf, sizeof(ventana_info))) {
>> +             printf("EEPROM: Failed to read EEPROM\n");
>> +             info->model[0] = 0;
>> +             return;
>> +     }
>> +
>> +     /* sanity checks */
>> +     if (info->model[0] != 'G' || info->model[1] != 'W') {
>> +             printf("EEPROM: Invalid Model in EEPROM\n");
>> +             info->model[0] = 0;
>> +             return;
>> +     }
>
> You can do your checks on the pyload after reading from the storage and
> using common functions.

Agreed, if I could use the common functions.  However here I am
reading from a device that requires some special handling (retry on
NAK).

>
>> +#ifdef CONFIG_CMD_GSC
>> +int read_hwmon(const char *name, uint reg, uint size, uint low, uint high)
>> +{
>> +     unsigned char buf[3];
>> +     uint ui;
>> +     int ret;
>> +
>> +     printf("%-8s:", name);
>> +     memset(buf, 0, sizeof(buf));
>> +     if (gsc_i2c_read(0x29, reg, 1, buf, size)) {
>> +             printf("fRD\n");
>> +             ret = -1;
>> +     } else {
>> +             ret = 0;
>> +             ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
>> +             if (ui == 0xffffff) {
>> +                     printf("fVL");
>> +             } else if (ui < low) {
>> +                     printf("%d fLO", ui);
>> +                     ret = -2;
>> +             } else if (ui > high) {
>> +                     printf("%d fHI", ui);
>> +                     ret = -3;
>> +             } else {
>> +                     printf("%d", ui);
>> +             }
>> +     }
>> +     printf("\n");
>> +
>> +     return ret;
>> +}
>
> I need help - I have not understood. This functions prints only
> something - return values is discarded when function is called. Buf is
> filled, but can you better explain the purpose of the function.

The gsc command (below) is currently just showing the values from the
hardware monitor (temp and various voltage rails).  The read_hwmon
function above is a helper function to display the value, or a failure
high, or failure low in a standard fashion.

>
>> +
>> +int do_gsc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>> +{
>> +     struct ventana_board_info *info = &ventana_info;
>> +
>> +     i2c_set_bus_num(0);
>> +     if ((strncasecmp((const char *)info->model, "GW51", 4) == 0)) {
>> +             read_hwmon("Temp",     0x00, 2, 0, 9000);
>> +             read_hwmon("VIN",      0x02, 3, 8000, 60000);
>> +             read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
>> +             read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
>> +             read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
>> +             read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
>> +             read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
>> +             read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
>> +             read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
>> +     } else if ((strncasecmp((const char *)info->model, "GW52", 4) == 0)) {
>> +             read_hwmon("Temp",     0x00, 2, 0, 9000);
>> +             read_hwmon("VIN",      0x02, 3, 8000, 60000);
>> +             read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
>> +             read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
>> +             read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
>> +             read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
>> +             read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
>> +             read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
>> +             read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
>> +             read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
>> +     } else if ((strncasecmp((const char *)info->model, "GW53", 4) == 0)) {
>> +             read_hwmon("Temp",     0x00, 2, 0, 9000);
>> +             read_hwmon("VIN",      0x02, 3, 8000, 60000);
>> +             read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
>> +             read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
>> +             read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
>> +             read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
>> +             read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
>> +             read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
>> +             read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
>> +             read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
>> +     } else if ((strncasecmp((const char *)info->model, "GW54", 4) == 0)) {
>> +             read_hwmon("Temp",     0x00, 2, 0, 9000);
>> +             read_hwmon("VIN",      0x02, 3, 8000, 60000);
>> +             read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
>> +             read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_CORE", 0x0e, 3, 1375*0.9, 1375*1.1);
>> +             read_hwmon("VDD_SOC",  0x11, 3, 1375*0.9, 1375*1.1);
>> +             read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
>> +             read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
>> +             read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
>> +             read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
>> +             read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
>> +             read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
>> +     }
>> +     return 0;
>> +}
>
> I think we can do better. Most cases are duplicated. Please split into
> common calls (for example, read_hwmon("Temp",     0x00, 2, 0, 9000) is
> always called) and board-variations. The identification is done on a
> single byte (GW51-GW54): you can use a more readable switch..case
> instead of multiple strncmp()

Agreed that there is a lot of duplication here.  I'll revise as the
only voltage rails not common across the 4 baseboards are VDD_SOC,
VDD_ARM, VDD_1P0.

I'm not sure I agree the switch-case is more readable although it
would be higher performance if that was something desirable.  The 4
gateworks baseboards get customized into 'specials' and sometimes
these specials end up with special handling based on models which is
why I like to keep the comparisons done as strings, but I suppose I
could cross that bridge if we come to it later.

>
>> +
>> +
>> +/* get_mac from env string, with default
>> + */
>> +static void get_mac(char *envvar, unsigned char *def)
>> +{
>> +     char str[20];
>> +     char *env = getenv(envvar);
>> +
>> +     if (!env) {
>> +             sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
>> +                     def[0], def[1], def[2], def[3], def[4], def[5]);
>> +             setenv(envvar, str);
>> +     }
>> +}
>
> No idea why you need it. The FEC driver takes care of MAC address and
> set the ethaddr variable. This seems to me wrong.

Agreed - I think this is a hold-over from when I started u-boot
support early last year.  I will remove.

>
<snip>
>> +
>> +int board_phy_config(struct phy_device *phydev)
>> +{
>> +     unsigned short val;
>> +
>> +     /* Marvel 88E1510 */
>> +     if (phydev->phy_id == 0x1410dd1) {
>> +             /* Errata 3.1 - PHY initialization */
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214b);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0c28);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb233);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214d);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xcc0c);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fb);
>> +             phy_write(phydev, MDIO_DEVAD_NONE,  7, 0xc00d);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
>> +
>
> This does not seem to me the best way to do. IMHO you should add support
> for Marvel 88E1510 in drivers/net/phy/, maybe as Alaska phy.

ok - I can do that.

>
> In board_phy_config() should contain only board specific initialization
> - an errata means that the same initialization is common to all boards
> having this chip.
>
>> +             /* LED configuration (See datasheet section 2.26.4)
>> +              * LED[0] (SPD:Amber) R16_3.3:0 to 0111: on-GbE link
>> +              * LED[1] (LNK:Green) R16_3.7:4 to 0001: on-link, blink-activity
>> +              */
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 22, 3);
>> +             val = phy_read(phydev, MDIO_DEVAD_NONE, 16);
>> +             val &= 0xff00;
>> +             val |= 0x0017;
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 16, val);
>> +             phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
>> +     }
>
> This is also part of the phy driver.

I would think LED configuration should be a board specific config as
its up to the board vendor what they want their LED's to do.

>
<snip>
>> +
>> +static void setup_board_gpio(const char *model)
>> +{
>> +     const char *s;
>> +     char arg[10];
>> +     size_t len;
>> +     int i;
>> +     enum {
>> +             GW51xx,
>> +             GW52xx,
>> +             GW53xx,
>> +             GW54xx,
>> +             UNKNOWN,
>> +     };
>> +     struct dio_cfg {
>> +             iomux_v3_cfg_t gpio_padmux;
>> +             unsigned gpio_param;
>> +             iomux_v3_cfg_t pwm_padmux;
>> +             unsigned pwm_param;
>> +     };
>> +     int board_type = UNKNOWN;
>> +     struct dio_cfg dio_cfg[] = {
>> +             /* GW51xx */
>> +             { 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 },
>> +
>> +             /* GW52xx */
>> +             { 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 },
>> +
>> +             /* GW53xx */
>> +             { 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 },
>> +
>> +             /* GW54xx */
>> +             { 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 },
>> +     };
>> +
>> +     if (strncasecmp(model, "GW51", 4) == 0) {
>> +             board_type = GW51xx;
>> +
>> +             /* PANLEDG# (GRN off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
>> +
>
> Again, this is not straightforward and difficult to read. Use tables for
> each board variation you want to add and split between common code and
> specific code.

Ok - I'll put all the pad config in a model specific array at least.

>
>> +             /* PANLEDR# (RED off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
>> +
>> +             /* GPS_SHDN */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_GPIO_2__GPIO1_IO02 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 2), 1);
>> +
>> +             /* Analog video codec power enable */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_CSI0_DATA_EN__GPIO5_IO20 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(5, 20), 1);
>> +
>> +             /* Expansion IO0 - PWREN# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
>> +
>> +             /* Expansion IO1 - IRQ# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_input(IMX_GPIO_NR(2, 18));
>> +     } /* end GW51xx */
>> +
>> +     else if (strncasecmp(model, "GW52", 4) == 0) {
>> +             board_type = GW52xx;
>> +
>> +             /* PANLEDG# (GRN off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
>> +
>> +             /* PANLEDR# (RED off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
>> +
>> +             /* MX6_LOCLED# (off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
>> +
>> +             /* GPS_SHDN */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_ENET_RXD0__GPIO1_IO27 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 27), 1);
>> +
>> +             /* Expansion IO0 - PWREN# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
>> +
>> +             /* Expansion IO1 - IRQ# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_input(IMX_GPIO_NR(2, 18));
>> +
>> +             /* MSATA Enable */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             if (is_cpu_type(MXC_CPU_MX6Q)) {
>> +                     gpio_direction_output(IMX_GPIO_NR(2, 8),
>> +                                           (hwconfig("msata")) ? 1 : 0);
>> +                     printf("MSATA: %s\n", (hwconfig("msata") ?
>> +                            "enabled" : "disabled"));
>> +             } else {
>> +                     gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
>> +             }
>> +
>> +             /* USBOTG Select (PCISKT or FrontPanel) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_GPIO_2__GPIO1_IO02 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 2), 0);
>> +
>> +             /* Analog video codec power enable */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
>> +
>> +             /* UART2_EN# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             printf("RS232: %s\n", (hwconfig("rs232")) ?
>> +                    "enabled" : "disabled");
>> +             gpio_direction_output(IMX_GPIO_NR(2, 11),
>> +                                   (hwconfig("rs232")) ? 0 : 1);
>> +             /* TODO: flush UART RX FIFO after disable */
>> +     } /* end GW52xx */
>> +
>> +     else if (strncasecmp(model, "GW53", 4) == 0) {
>> +             board_type = GW53xx;
>> +
>> +             /* PANLEDG# (GRN off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
>> +
>> +             /* PANLEDR# (RED off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
>> +
>> +             /* MX6_LOCLED# (off) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
>> +
>> +             /* GPS_SHDN */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_ENET_RXD0__GPIO1_IO27 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 27), 1);
>> +
>> +             /* Expansion IO0 - PWREN# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
>> +
>> +             /* Expansion IO1 - IRQ# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_input(IMX_GPIO_NR(2, 18));
>> +
>> +             /* MSATA Enable */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             if (is_cpu_type(MXC_CPU_MX6Q)) {
>> +                     gpio_direction_output(IMX_GPIO_NR(2, 8),
>> +                                           (hwconfig("msata")) ? 1 : 0);
>> +                     printf("MSATA: %s\n", (hwconfig("msata") ?
>> +                            "enabled" : "disabled"));
>> +             } else {
>> +                     gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
>> +             }
>> +
>> +             /* Analog video codec power enable */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
>> +
>> +             /* UART2_EN# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             printf("RS232: %s\n", (hwconfig("rs232")) ?
>> +                    "enabled" : "disabled");
>> +             gpio_direction_output(IMX_GPIO_NR(2, 11),
>> +                                   (hwconfig("rs232")) ? 0 : 1);
>> +             /* TODO: flush UART RX FIFO after disable */
>> +     } /* end GW53xx */
>> +
>> +     else if (strncasecmp(model, "GW54", 4) == 0) {
>> +             board_type = GW54xx;
>> +             if (strncasecmp(model, "GW5400-A", 8) == 0) {
>> +                     /* PANLEDG# (GRN off) */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
>> +
>> +                     /* PANLEDR# (RED off) */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL2__GPIO4_IO10 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 10), 1);
>> +
>> +                     /* MX6_LOCLED# (off) */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
>> +
>> +                     /* MIPI DIO */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT3__GPIO1_IO21 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +
>> +                     /* RS485 Transmit Enable */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_EIM_D24__GPIO3_IO24 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(3, 24), 0);
>> +
>> +                     /* Expansion IO0 - PWREN# */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 7), 0);
>> +
>> +                     /* Expansion IO1 - IRQ# */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW1__GPIO4_IO09 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_input(IMX_GPIO_NR(4, 9));
>> +             }
>> +
>> +             else if ((strncasecmp(model, "GW5400", 6) == 0) ||
>> +                      (strncasecmp(model, "GW5410", 6) == 0)
>> +             ) {
>> +                     /* PANLEDG# (GRN off) */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
>> +
>> +                     /* PANLEDR# (RED off) */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
>> +
>> +                     /* MX6_LOCLED# (off) */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
>> +
>> +                     /* RS485 Transmit Enable */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_SD3_DAT4__GPIO7_IO01 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(7, 1), 0);
>> +
>> +                     /* Expansion IO0 - PWREN# */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
>> +
>> +                     /* Expansion IO1 - IRQ# */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_input(IMX_GPIO_NR(2, 18));
>> +
>> +                     /* MSATA Enable */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     if (is_cpu_type(MXC_CPU_MX6Q)) {
>> +                             gpio_direction_output(IMX_GPIO_NR(2, 8),
>> +                                                   (hwconfig("msata")) ?
>> +                                                   1 : 0);
>> +                             printf("MSATA: %s\n", (hwconfig("msata") ?
>> +                                    "enabled" : "disabled"));
>> +                     } else {
>> +                             gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
>> +                     }
>> +
>> +                     /* Analog video codec power enable */
>> +                     imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +                     gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
>> +             }
>> +
>> +             /* UART2_EN# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
>> +                                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             printf("RS232: %s\n", (hwconfig("rs232")) ?
>> +                    "enabled" : "disabled");
>> +             gpio_direction_output(IMX_GPIO_NR(2, 11),
>> +                                   (hwconfig("rs232")) ? 0 : 1);
>> +             /* TODO: flush UART RX FIFO after disable */
>> +
>> +             /* DIOI2C_DIS# */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_GPIO_19__GPIO4_IO05 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(4,  5), 0);
>> +     } /* end GW54xx */
>> +
>> +     /* Configure DIO pinmux/padctl registers
>> +      * see IMX6DQRM/IMX6SDLRM IOMUXC_SW_PAD_CTL_PAD_* register definitions
>> +      */
>> +     if (board_type > UNKNOWN)
>> +             return;
>> +     for (i = 0; i < 4; i++) {
>> +             struct dio_cfg *cfg = &dio_cfg[(4*board_type)+i];
>> +             unsigned ctrl = DIO_PAD_CTRL;
>> +
>> +             sprintf(arg, "dio%d", i);
>> +             if (hwconfig(arg)) {
>> +                     s = hwconfig_subarg(arg, "padctrl", &len);
>> +                     if (s)
>> +                             ctrl = simple_strtoul(s, NULL, 16) & 0x3ffff;
>> +                     if (hwconfig_subarg_cmp(arg, "mode", "gpio")) {
>> +                             printf("DIO%d:  GPIO%d_IO%02d (gpio-%d)\n", i,
>> +                                    (cfg->gpio_param/32)+1,
>> +                                    cfg->gpio_param%32,
>> +                                    cfg->gpio_param);
>> +                             imx_iomux_v3_setup_pad(cfg->gpio_padmux |
>> +                                                    MUX_PAD_CTRL(ctrl));
>> +                             gpio_direction_input(cfg->gpio_param);
>> +                     } else if (hwconfig_subarg_cmp("dio2", "mode", "pwm") &&
>> +                                cfg->pwm_padmux) {
>> +                             printf("DIO%d:  pwm%d\n", i, cfg->pwm_param);
>> +                             imx_iomux_v3_setup_pad(cfg->pwm_padmux |
>> +                                                    MUX_PAD_CTRL(ctrl));
>> +                     }
>> +             }
>> +     }
>> +}
>> +
>> +static int setup_pcie(void)
>> +{
>> +     struct ventana_board_info *info = &ventana_info;
>> +
>> +     if ((strncasecmp((const char *)info->model, "GW51", 4) == 0)) {
>> +             /* assert PCI_RST#
>> +              * (will be released by OS when clock is valid) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_GPIO_0__GPIO1_IO00 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 0), 0);
>> +     } else if ((strncasecmp((const char *)info->model, "GW52", 4) == 0)) {
>> +             /* assert PCI_RST#
>> +              * (will be released by OS when clock is valid) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
>> +     } else if ((strncasecmp((const char *)info->model, "GW53", 4) == 0)) {
>> +             /* assert PCI_RST#
>> +              * (will be released by OS when clock is valid) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
>> +     } else if ((strncasecmp((const char *)info->model, "GW54", 4) == 0)) {
>> +             /* PCICK_SSON: disable spread-spectrum clock */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_SD1_CLK__GPIO1_IO20 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 20), 0);
>> +
>> +             /* assert PCI_RST#
>> +              * (will be released by OS when clock is valid) */
>> +             imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
>> +                                    MUX_PAD_CTRL(NO_PAD_CTRL));
>> +             gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
>> +     }
>> +
>> +     return 0;
>> +}
>
> Please take a look at Marek's later merged patches that add PCI-E
> support for i.MX6 to U-Boot, and rebase on top of it. I can suggest to
> use u-boot-imx as base for your patches, because patches are already merged.

I'm aware of Marek's patches but wasn't sure when they were scheduled
to go in.  I will rebase against u-boot-imx and put the above in the
new imx6_pcie_toggle_reset function.

>
> Generally, I think you should change the behavior of selecting data on
> depend of the board. Instead of checkig in each function which is the
> board, you should add table containinig all required values, and choose
> one of them in only one function.

pcie reset, gpio default configuration (pinmux and direction/level),
and the hwmon registers are the only places that are model dependent.
I feel it is more readable to leave the model checks in place instead
of trying to create structures that have all of that in them.

>
>> +
>> +#if defined(CONFIG_VIDEO_IPUV3)
>> +
>> +static iomux_v3_cfg_t const backlight_pads[] = {
>> +     /* Backlight on MIPI connector: J16 */
>> +     MX6_PAD_SD2_CMD__GPIO1_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
>> +
>> +     /* Backlight CABEN on LVDS connector: J6 */
>> +     MX6_PAD_SD2_CLK__GPIO1_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
>> +};
>> +
>> +struct display_info_t {
>> +     int     bus;
>> +     int     addr;
>> +     int     pixfmt;
>> +     int     (*detect)(struct display_info_t const *dev);
>> +     void    (*enable)(struct display_info_t const *dev);
>> +     struct  fb_videomode mode;
>> +};
>> +
>> +
>> +static int detect_hdmi(struct display_info_t const *dev)
>> +{
>> +     struct hdmi_regs *hdmi  = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR;
>> +     return readb(&hdmi->phy_stat0) & HDMI_PHY_HPD;
>> +}
>> +
>> +static void do_enable_hdmi(struct display_info_t const *dev)
>> +{
>> +     imx_enable_hdmi_phy();
>> +}
>> +
>> +static int detect_i2c(struct display_info_t const *dev)
>> +{
>> +     return ((0 == i2c_set_bus_num(dev->bus)) &&
>> +             (0 == i2c_probe(dev->addr)));
>> +}
>> +
>> +static void enable_lvds(struct display_info_t const *dev)
>> +{
>> +     struct iomuxc *iomux = (struct iomuxc *)
>> +                             IOMUXC_BASE_ADDR;
>> +
>> +     /* set CH0 data width to 24bit (IOMUXC_GPR2:5 0=18bit, 1=24bit) */
>> +     u32 reg = readl(&iomux->gpr[2]);
>> +     reg |= IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT;
>> +     writel(reg, &iomux->gpr[2]);
>> +
>> +     /* Disable CABC:
>> +      * when enabled this feature sets backlight automatically according
>> +      * to content which may cause annoying unstable backlight issue
>> +      */
>> +     gpio_direction_output(IMX_GPIO_NR(1, 10), 0);
>> +
>> +     /* Enable Backlight */
>> +     imx_iomux_v3_setup_pad(MX6_PAD_SD1_CMD__GPIO1_IO18 |
>> +                            MUX_PAD_CTRL(NO_PAD_CTRL));
>> +     gpio_direction_output(IMX_GPIO_NR(1, 18), 1);
>> +}
>> +
>> +static struct display_info_t const displays[] = {{
>> +     /* HDMI Output */
>> +     .bus    = -1,
>> +     .addr   = 0,
>> +     .pixfmt = IPU_PIX_FMT_RGB24,
>> +     .detect = detect_hdmi,
>> +     .enable = do_enable_hdmi,
>> +     .mode   = {
>> +             .name           = "HDMI",
>> +             .refresh        = 60,
>> +             .xres           = 1024,
>> +             .yres           = 768,
>> +             .pixclock       = 15385,
>> +             .left_margin    = 220,
>> +             .right_margin   = 40,
>> +             .upper_margin   = 21,
>> +             .lower_margin   = 7,
>> +             .hsync_len      = 60,
>> +             .vsync_len      = 10,
>> +             .sync           = FB_SYNC_EXT,
>> +             .vmode          = FB_VMODE_NONINTERLACED
>> +} }, {
>> +     /* HannStar HSD100PXN1-A00 with egalx_ts controller
>> +      * (aka Freescale MXC-LVDS1 10" 1024x768 60Hz LCD touchscreen)
>> +      */
>> +     .bus    = 2,
>> +     .addr   = 0x4,
>> +     .pixfmt = IPU_PIX_FMT_LVDS666,
>> +     .detect = detect_i2c,
>> +     .enable = enable_lvds,
>> +     .mode   = {
>> +             .name           = "Hannstar-XGA",
>> +             .refresh        = 60,
>> +             .xres           = 1024,
>> +             .yres           = 768,
>> +             .pixclock       = 15385,
>> +             .left_margin    = 220,
>> +             .right_margin   = 40,
>> +             .upper_margin   = 21,
>> +             .lower_margin   = 7,
>> +             .hsync_len      = 60,
>> +             .vsync_len      = 10,
>> +             .sync           = FB_SYNC_EXT,
>> +             .vmode          = FB_VMODE_NONINTERLACED
>> +} } };
>> +
>> +int board_video_skip(void)
>> +{
>> +     int i;
>> +     int ret;
>> +     char const *panel = getenv("panel");
>> +     if (!panel) {
>> +             for (i = 0; i < ARRAY_SIZE(displays); i++) {
>> +                     struct display_info_t const *dev = displays+i;
>> +                     if (dev->detect(dev)) {
>> +                             panel = dev->mode.name;
>> +                             printf("auto-detected panel %s\n", panel);
>> +                             break;
>> +                     }
>> +             }
>> +             if (!panel) {
>> +                     panel = displays[0].mode.name;
>> +                     i = 0;
>> +                     printf("No panel detected: default to %s\n", panel);
>> +             }
>> +     } else {
>> +             for (i = 0; i < ARRAY_SIZE(displays); i++) {
>> +                     if (!strcmp(panel, displays[i].mode.name))
>> +                             break;
>> +             }
>> +     }
>> +     if (i < ARRAY_SIZE(displays)) {
>> +             ret = ipuv3_fb_init(&displays[i].mode, 0,
>> +                                 displays[i].pixfmt);
>> +             if (!ret) {
>> +                     displays[i].enable(displays+i);
>> +                     printf("DISP:  %s (%ux%u)\n",
>> +                            displays[i].mode.name,
>> +                            displays[i].mode.xres,
>> +                            displays[i].mode.yres);
>> +             } else
>> +                     printf("LCD %s cannot be configured: %d\n",
>> +                            displays[i].mode.name, ret);
>> +     } else {
>> +             printf("unsupported panel %s\n", panel);
>> +             ret = -EINVAL;
>> +     }
>> +     return (0 != ret);
>> +
> }
>
> Nak. This function is more or less copied from another board. There is
> still a patch doing this and my suggestion is to factorize the part in
> board_video_skip(), taht is not really strict bound to the board.

Yes, both mx6sabresd and nitrogen6x use this common code and I saw the
proposed patch to add it to wandboard as well with your response
asking for it to be made common.  I'll check with Otavio to see if he
is working on something already.  I agree some common support could
help here.

>
>> +
>> +static void setup_display(void)
>> +{
>> +     struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
>> +     struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
>> +     int reg;
>> +
>> +     enable_ipu_clock();
>> +     imx_setup_hdmi();
>> +
>> +     /* Turn on LDB0,IPU,IPU DI0 clocks */
>> +     reg = readl(&mxc_ccm->CCGR3);
>> +     reg |= MXC_CCM_CCGR3_LDB_DI0_MASK;
>> +     writel(reg, &mxc_ccm->CCGR3);
>> +
>> +     /* set LDB0, LDB1 clk select to 011/011 */
>> +     reg = readl(&mxc_ccm->cs2cdr);
>> +     reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
>> +              |MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
>> +     reg |= (3<<MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
>> +           |(3<<MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
>> +     writel(reg, &mxc_ccm->cs2cdr);
>> +
>> +     reg = readl(&mxc_ccm->cscmr2);
>> +     reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
>> +     writel(reg, &mxc_ccm->cscmr2);
>> +
>> +     reg = readl(&mxc_ccm->chsccdr);
>> +     reg |= (CHSCCDR_CLK_SEL_LDB_DI0
>> +             <<MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
>> +     writel(reg, &mxc_ccm->chsccdr);
>> +
>> +     reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
>> +          |IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
>> +          |IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
>> +          |IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
>> +          |IOMUXC_GPR2_DATA_WIDTH_CH1_18BIT
>> +          |IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
>> +          |IOMUXC_GPR2_DATA_WIDTH_CH0_18BIT
>> +          |IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
>> +          |IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
>> +     writel(reg, &iomux->gpr[2]);
>> +
>> +     reg = readl(&iomux->gpr[3]);
>> +     reg = (reg & ~IOMUXC_GPR3_LVDS0_MUX_CTL_MASK)
>> +         | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
>> +            <<IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
>> +     writel(reg, &iomux->gpr[3]);
>> +
>> +     /* backlights off until needed */
>> +     imx_iomux_v3_setup_multiple_pads(backlight_pads,
>> +                                      ARRAY_SIZE(backlight_pads));
>> +     gpio_direction_input(IMX_GPIO_NR(1, 10)); /* LVDS */
>> +     gpio_direction_input(IMX_GPIO_NR(1, 11)); /* MIPI */
>> +}
>> +#endif /* CONFIG_VIDEO_IPUV3 */
>> +
>> +static int setup_pmic_voltages(void)
>> +{
>> +     int ret;
>> +     unsigned char value, rev_id = 0;
>> +
>> +     ret = i2c_set_bus_num(1);
>> +     if (ret)
>> +             return ret;
>> +     if (!i2c_probe(0x8)) {
>
> Nak. We have a generic PMIX framework. Please use it.

agreed - I see that now and will revise.

>
>> +/*
>> + * Board Support
>> + */
>> +
>> +/*
>> + * Do not overwrite the console
>> + * Use always serial for U-Boot console
>> + */
>> +int overwrite_console(void)
>
> This is not required, please drop it.

will do

>
>> +{
>> +     return 1;
>> +}
>> +
>> +
>> +/*
>> + * very early in the call chain - setup SoC peripherals
>> + * (NB: Can not printf from here)
>> + */
>> +int board_early_init_f(void)
>> +{
>> +     setup_iomux_uart();
>> +#ifdef CONFIG_MXC_SPI
>> +     setup_spi();
>
>  board_early_init_f() is called before relocation and malloc() is not
> available. SPI uses malloc(), then you should move setup_spi to a later
> point.

ok - will move.

>
>> +#endif
>> +     gpio_direction_output(IMX_GPIO_NR(3, 22), 0); /* OTG power off */
>> +
>> +     /* Note this gets called again later,
>> +      * but needed in case i2c bus is stuck */
>> +     timer_init();
>
> timer_init() ? I think this is called by generic code.

it is, but as the common states its called later (at least it was when
I first wrote this) and causes one of the error handling functions to
hang when it tries to delay.  The specific issue I was working around
here had to do with no console output from the bootloader if you had
for example an HDMI monitor plugged in with a bad EDID clk/data pin.

I'll check to see if this is still needed as this code was written and
tested some time ago.

>
>> +     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 defined(CONFIG_VIDEO_IPUV3)
>> +     setup_display();
>> +#endif
>> +
>> +     return 0;
>> +}
>> +
>> +#if defined(CONFIG_DISPLAY_BOARDINFO)
>> +/* Identify board and display banner/info
>> + */
>> +#define SRC_SBMR1 0x020d8004  /* holds BOOT_CFG1-BOOT_CFG4 from eFuse/pins */
>> +#define SRC_SBMR2 0x020d801c
>> +#define SRC_GPR9  0x020d8040  /* holds copy of BOOT_CFG1-BOOT_CFG4 acted on */
>> +#define SRC_GPR10 0x020d8044
>> +
>
> No access to internal register using absolute addresses. Use structures
> in imx_regs.h. that is struct src->sbmrX

ack

>
>> +/* this reads boot_cfg efuse/pins - does not reflect what actually booted
>> + */
>> +void show_boot_mode(uint boot_cfg)
>> +{
>> +     switch ((boot_cfg & 0x000000ff) >> 4) {
>> +     case 0x2:
>> +             printf("SATA");
>> +             break;
>> +     case 0x3:
>> +             printf("SPI NOR");
>> +             break;
>> +     case 0x4:
>> +     case 0x5:
>> +             /* BOOT_CFG2[3:4] is devno */
>> +             printf(" SD%d", (boot_cfg & 0x00001800) >> 11);
>> +             break;
>> +     case 0x6:
>> +     case 0x7:
>> +             /* BOOT_CFG2[3:4] is devno */
>> +             printf(" MMC%d", (boot_cfg & 0x00001800) >> 11);
>> +             break;
>> +     case 0x8 ... 0xf:
>> +             printf("NAND");
>> +             break;
>> +     default:
>> +             printf("Unknown");
>> +             break;
>> +     }
>> +     printf(" 0x%08x\n", boot_cfg);
>> +}
>> +
>
> This does not belog here. Please move this code in a separate patch and
> make it available to all boards. Code should flow into
> ./arch/arm/imx-common. Please add a function getting an enumated value
> as return value, not only a function that output the result.
>
> Use puts() instead of printf() if you print a constant string.
>
> Instead of:
>                 printf("NAND");
>
> Use:
>                 puts("NAND");
>

ack

>> +
>> +int checkboard(void)
>> +{
>> +     struct ventana_board_info *info = &ventana_info;
>> +     uint src_sbmr2 = readl(SRC_SBMR2);
>> +     uint src_gpr10 = readl(SRC_GPR10);
>> +
>> +     /* check for valid i2c busses - if one was 'stuck' it did not get
>> +      * initialized
>> +      */
>> +     if (i2c_set_bus_num(0))
>> +             printf("invalid /dev/i2c-0\n");
>
> /dev has no meaning in U-Boot.

will fix

>
>> +     if (i2c_set_bus_num(1))
>> +             printf("invalid /dev/i2c-1\n");
>> +     if (i2c_set_bus_num(2))
>> +             printf("invalid /dev/i2c-2\n");
>> +     read_eeprom();
>> +     if (!(src_sbmr2 & 1<<4)) {
>> +             /* can consider this 'manufacturing mode' if needed */
>> +             printf("First boot - eFUSE not blown\n");
>> +     }
>> +
>> +     printf("APP_IMAGE: %s\n", (src_gpr10 & 1<<30) ?
>> +            "Secondary" : "Primary");
>> +     if (src_gpr10 & 1<<29)
>> +             printf("NAND: bad blocks in application image\n");
>> +
>> +#if defined(CONFIG_ENV_IS_IN_SPI_FLASH)
>> +     printf("Env: SPI FLASH\n");
>> +#elif defined(CONFIG_ENV_IS_IN_MMC)
>> +     printf("Env: MMC\n");
>> +#elif defined(CONFIG_ENV_IS_IN_NAND)
>> +     printf("Env: NAND FLASH\n");
>> +#endif
>> +
>> +     /* SRC_SBMR1 reflects eFUSE/pin */
>> +     printf("BOOT_CFG: ");
>> +     show_boot_mode(readl(SRC_SBMR1));
>> +     /* SRC_GPR9 reflects what was actually booted off of if not 0
>> +      * (ie if bmode was used) */
>> +     if (readl(SRC_GPR9)) {
>> +             printf("BMODE: ");
>> +             show_boot_mode(readl(SRC_GPR9));
>> +     }
>> +     printf("\n");
>> +     printf("Gateworks Corporation Copyright 2014\n");
>> +     if (info->model[0]) {
>> +             printf("Model: %s\n", info->model);
>> +             printf("MFGDate: %02x-%02x-%02x%02x\n",
>> +                    info->mfgdate[0], info->mfgdate[1],
>> +                    info->mfgdate[2], info->mfgdate[3]);
>> +             printf("Serial:%d\n", info->serial);
>> +     } else {
>> +             printf("Invalid EEPROM - board will not function fully\n");
>> +     }
>> +
>> +     return 0;
>> +}
>> +#endif
>
> General remak: you print a lot of stuff by booting. This can slow down
> your boot process significantly adding several seconds to your start up,
> before the kernel is loaded.

agreed - perhaps there are some common defines I can use to quiet
things down by default or even better an env variable that the user
can set?

We've found that showing the boot device, and model in the bootloader
is extremely helpfull in supporting users but I suppose I could move
some of the other things like DIO/SATA/RS232 configuration (hwconfig
controlled) reporting to a user command.

>
>> +
>> +/* Set gd->ram_size
>> + */
>> +int dram_init(void)
>> +{
>> +     struct ventana_board_info *info = &ventana_info;
>> +
>> +     gd->ram_size = ((ulong)CONFIG_DDR_MB * 1024 * 1024);
>> +     if (info->model[0] && info->sdram_size > 0 && info->sdram_size < 9) {
>> +             int i = info->sdram_size;
>> +             gd->ram_size = 32*1024*1024;
>> +             while (--i)
>> +                     gd->ram_size *= 2;
>> +     }
>
> Use get_ramsize to dynamically find the size of the installed RAM.

will do - looking at doc/README.memory-test it seems that
get_ram_size() should be very fast and can also catch hardware related
memory errors.

>
>> +/* initialize periperhals
>> + */
>> +int board_init(void)
>> +{
>> +     int ret = 0;
>> +     struct iomuxc_base_regs *const iomuxc_regs
>> +             = (struct iomuxc_base_regs *)IOMUXC_BASE_ADDR;
>> +
>> +#ifdef CONFIG_CMD_NAND
>> +     setup_gpmi_nand();
>> +#endif
>> +
>> +     clrsetbits_le32(&iomuxc_regs->gpr[1],
>> +                     IOMUXC_GPR1_OTG_ID_MASK,
>> +                     IOMUXC_GPR1_OTG_ID_GPIO1);
>> +
>> +     imx_iomux_v3_setup_multiple_pads(usb_pads, ARRAY_SIZE(usb_pads));
>> +
>> +     /* address of linux boot parameters */
>> +     gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
>> +
>> +#ifdef CONFIG_SYS_I2C_MXC
>> +     ret = setup_pmic_voltages();
>> +     if (ret)
>> +             return -1;
>> +#endif
>> +
>> +     setup_pcie();
>> +
>> +#ifdef CONFIG_CMD_SATA
>> +     setup_sata();
>> +#endif
>> +
>> +     if (!i2c_set_bus_num(0)) {
>> +             unsigned char buf[4];
>> +             if (!gsc_i2c_read(0x20, 14, 1, buf, 1)) {
>> +                     printf("GSC:   v%d", buf[0]);
>> +                     if (!gsc_i2c_read(0x20, 10, 1, buf, 4)) {
>> +                             /* show firmware revision and CRC */
>> +                             printf(" 0x%04x", buf[2] | buf[3]<<8);
>> +                             /* show status register */
>
> I do not understand the code here. This should belong to checkboard().

it is displaying info about firmware revision and status of GSC - I
will move it to checkboard().

>
>> +/* late init
>> + */
>> +int misc_init_r(void)
>> +{
>> +     /* set env vars based on board model from EEPROM */
>> +     if (ventana_info.model[0]) {
>> +             char str[sizeof(ventana_info.model)];
>> +             char fdt[sizeof(ventana_info.model)+20];
>> +             char *p;
>> +             int i;
>> +             const char *prefix = "";
>> +
>> +             if (is_cpu_type(MXC_CPU_MX6Q))
>> +                     prefix = "imx6q";
>> +             else if (is_cpu_type(MXC_CPU_MX6DL))
>> +                     prefix = "imx6dl";
>> +
>> +             memset(str, 0, sizeof(str));
>> +             for (i = 0; i < (sizeof(ventana_info.model)-1) &&
>> +                  ventana_info.model[i]; i++)
>> +                     str[i] = tolower(ventana_info.model[i]);
>> +             if (!getenv("model"))
>> +                     setenv("model", str);
>> +             if (!getenv("fdt_file")) {
>> +                     sprintf(fdt, "%s-%s.dtb", prefix, str);
>> +                     setenv("fdt_file", fdt);
>> +             }
>> +             p = strchr(str, '-');
>> +             if (p) {
>> +                     *p++ = 0;
>> +
>> +                     setenv("model_base", str);
>> +                     if (!getenv("fdt_file1")) {
>> +                             sprintf(fdt, "%s-%s.dtb", prefix, str);
>> +                             setenv("fdt_file1", fdt);
>> +                     }
>> +                     str[4] = 'x';
>> +                     str[5] = 'x';
>> +                     str[6] = 0;
>> +                     if (!getenv("fdt_file2")) {
>> +                             sprintf(fdt, "%s-%s.dtb", prefix, str);
>> +                             setenv("fdt_file2", fdt);
>> +                     }
>> +             }
>> +             get_mac("ethaddr", ventana_info.mac0);
>> +             get_mac("eth1addr", ventana_info.mac1);
>> +             sprintf(str, "%6d", ventana_info.serial);
>> +             setenv("serial#", str);
>> +             setup_board_gpio(getenv("model"));
>> +     }
>> +
>> +     /* generate a random eth mac if no EEPROM (1st boot - mfg mode) */
>> +     else {
>> +             u32 ethaddr_low, ethaddr_high;
>> +             char str[20];
>> +
>> +             /* use Device Unique ID bits 0-64 from eFUSE
>> +              * (OCOTP_CFG1/OCOTP_CFG2) */
>> +             fuse_read(0, 1, &ethaddr_low);
>> +             fuse_read(0, 2, &ethaddr_high);
>> +
>> +             /*
>> +              * setting the 2nd LSB in the most significant byte of
>> +              * the address makes it a locally administered ethernet
>> +              * address
>> +              */
>> +             ethaddr_high &= 0xfeff;
>> +             ethaddr_high |= 0x0200;
>> +             sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
>> +                     ethaddr_high >> 8, ethaddr_high & 0xff,
>> +                     ethaddr_low >> 24, (ethaddr_low >> 16) & 0xff,
>> +                     (ethaddr_low >> 8) & 0xff, ethaddr_low & 0xff);
>> +             printf("### Setting random MAC address = \"%s\"\n", str);
>> +             setenv("ethaddr", str);
>> +     }
>
> Apart that this functionality should not be added to misc_init(), but to
> the corresponding entry point (board_eth_init for example), I do not
> think it is correct. If a random address can be generated, it should be
> part of the FEC driver. The FEC already reads from fuses, that makes the
> code here useless.

Agreed - I never noticed that was available in common code.  I will remove it.

>
>> +
>> +#ifdef CONFIG_CMD_BMODE
>> +     add_board_boot_modes(board_boot_modes);
>> +#endif
>> +
>> +     /* disable GSC boot watchdog
>> +      *
>> +      *  The Gateworks System Controller implements a boot
>> +      *  watchdog (always enabled) to cover things like ERR006282 which can
>> +      *  lead to random boot failures.
>> +      */
>> +     if (!i2c_set_bus_num(0)) {
>> +             unsigned char val;
>> +             if (!gsc_i2c_read(0x20, 1, 1, &val, 1)) {
>> +                     val |= 0x80;
>> +                     if (gsc_i2c_write(0x20, 1, 1, &val, 1))
>> +                             printf("Error: could not disable GSC Watchdog\n");
>> +             } else {
>> +                     printf("Error: could not disable GSC Watchdog\n");
>> +             }
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
>> +void ft_board_setup(void *blob, bd_t *bd)
>> +{
>> +     struct ventana_board_info *info = &ventana_info;
>> +     struct node_info nodes[] = {
>> +             { "sst,w25q256",          MTD_DEV_TYPE_NOR, },  /* SPI flash */
>> +             { "fsl,imx6q-gpmi-nand",  MTD_DEV_TYPE_NAND, }, /* NAND flash */
>> +     };
>> +     const char *model = getenv("model");
>> +
>> +     if (getenv("fdt_noauto")) {
>> +             printf("   Skiping ft_board_setup (fdt_noauto defined)\n");
>> +             return;
>> +     }
>> +
>> +     /* MTD partitions
>> +      * Update partition nodes using info from mtdparts env var
>> +      */
>> +     printf("   Updating MTD partitions...\n");
>> +     fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
>> +
>> +     if (!model) {
>> +             printf("invalid board info: Leaving FDT fully enabled\n");
>> +             return;
>> +     }
>> +     printf("   Adjusting FDT per EEPROM for %s...\n", model);
>> +
>> +     /* Note that fdt_fixup_ethernet is called in arm/lib/bootm before this
>> +      * which sets mac-address and local-mac-address properties of
>> +      * ethernet<n> aliases to ethaddr...eth<n>addr env
>> +      */
>> +
>> +     /* board serial number */
>> +     fdt_setprop(blob, 0, "system-serial", getenv("serial#"),
>> +                 strlen(getenv("serial#") + 1));
>> +
>> +     /* board (model contains model from device-tree) */
>> +     fdt_setprop(blob, 0, "board", info->model,
>> +                 strlen((const char *)info->model) + 1);
>> +
>> +     /* Peripheral Config */
>> +     if (!info->config_eth0)
>> +             fdt_del_node_and_alias(blob, "ethernet0");
>> +     if (!info->config_eth1)
>> +             fdt_del_node_and_alias(blob, "ethernet1");
>> +     if (!info->config_hdmi_out)
>> +             fdt_del_node_and_alias(blob, "hdmi_out");
>> +     if (!info->config_sata)
>> +             fdt_del_node_and_alias(blob, "ahci0");
>> +     if (!info->config_pcie)
>> +             fdt_del_node_and_alias(blob, "pcie");
>> +     if (!info->config_ssi0)
>> +             fdt_del_node_and_alias(blob, "ssi0");
>> +     if (!info->config_ssi1)
>> +             fdt_del_node_and_alias(blob, "ssi1");
>> +     if (!info->config_lcd)
>> +             fdt_del_node_and_alias(blob, "lcd0");
>> +     if (!info->config_lvds0)
>> +             fdt_del_node_and_alias(blob, "lvds0");
>> +     if (!info->config_lvds1)
>> +             fdt_del_node_and_alias(blob, "lvds1");
>> +     if (!info->config_usb0)
>> +             fdt_del_node_and_alias(blob, "usb0");
>> +     if (!info->config_usb1)
>> +             fdt_del_node_and_alias(blob, "usb1");
>> +     if (!info->config_sd0)
>> +             fdt_del_node_and_alias(blob, "usdhc0");
>> +     if (!info->config_sd1)
>> +             fdt_del_node_and_alias(blob, "usdhc1");
>> +     if (!info->config_sd2)
>> +             fdt_del_node_and_alias(blob, "usdhc2");
>> +     if (!info->config_sd3)
>> +             fdt_del_node_and_alias(blob, "usdhc3");
>> +     if (!info->config_uart0)
>> +             fdt_del_node_and_alias(blob, "serial0");
>> +     if (!info->config_uart1)
>> +             fdt_del_node_and_alias(blob, "serial1");
>> +     if (!info->config_uart2)
>> +             fdt_del_node_and_alias(blob, "serial2");
>> +     if (!info->config_uart3)
>> +             fdt_del_node_and_alias(blob, "serial3");
>> +     if (!info->config_uart4)
>> +             fdt_del_node_and_alias(blob, "serial4");
>> +     if (!info->config_ipu0)
>> +             fdt_del_node_and_alias(blob, "ipu0");
>> +     if (!info->config_ipu1)
>> +             fdt_del_node_and_alias(blob, "ipu1");
>> +     if (!info->config_flexcan)
>> +             fdt_del_node_and_alias(blob, "can0");
>> +     if (!info->config_mipi_dsi)
>> +             fdt_del_node_and_alias(blob, "mipi_dsi");
>> +     if (!info->config_mipi_csi)
>> +             fdt_del_node_and_alias(blob, "mipi_csi");
>> +     if (!info->config_tzasc0)
>> +             fdt_del_node_and_alias(blob, "tzasc0");
>> +     if (!info->config_tzasc1)
>> +             fdt_del_node_and_alias(blob, "tzasc1");
>> +     if (!info->config_i2c0)
>> +             fdt_del_node_and_alias(blob, "i2c0");
>> +     if (!info->config_i2c1)
>> +             fdt_del_node_and_alias(blob, "i2c1");
>> +     if (!info->config_i2c2)
>> +             fdt_del_node_and_alias(blob, "i2c2");
>> +     if (!info->config_vpu)
>> +             fdt_del_node_and_alias(blob, "vpu");
>> +     if (!info->config_csi0)
>> +             fdt_del_node_and_alias(blob, "csi0");
>> +     if (!info->config_csi1)
>> +             fdt_del_node_and_alias(blob, "csi1");
>> +     if (!info->config_caam)
>> +             fdt_del_node_and_alias(blob, "caam");
>> +     if (!info->config_espci0)
>> +             fdt_del_node_and_alias(blob, "spi0");
>> +     if (!info->config_espci1)
>> +             fdt_del_node_and_alias(blob, "spi1");
>> +     if (!info->config_espci2)
>> +             fdt_del_node_and_alias(blob, "spi2");
>> +     if (!info->config_espci3)
>> +             fdt_del_node_and_alias(blob, "spi3");
>> +     if (!info->config_espci4)
>> +             fdt_del_node_and_alias(blob, "spi4");
>> +     if (!info->config_espci5)
>> +             fdt_del_node_and_alias(blob, "spi5");
>> +     if (!info->config_hdmi_in)
>> +             fdt_del_node_and_alias(blob, "hdmi_in");
>> +     if (!info->config_vid_out)
>> +             fdt_del_node_and_alias(blob, "cvbs_out");
>> +     if (!info->config_vid_in)
>> +             fdt_del_node_and_alias(blob, "cvbs_in");
>> +     if (!info->config_nand)
>> +             fdt_del_node_and_alias(blob, "nand");
>> +     if (!info->config_gps)
>> +             fdt_del_node_and_alias(blob, "pps");
>
> I find the way quite singular. It seems you have a full-blown .dts file
> and you want to drop the features that you do not find in eeprom. A more
> conventional way is to have a simpler or not fully configured dts and
> add only the feature you want.

Yes, this is what I am doing - removing nodes from a full-featured devicetree.

I feel it better represents the board to have the 'full featured'
version present in the upstream Linux kernel and to simply disable
nodes that are removed.  Also, adding features instead would add a lot
of code here as the whole dts representation of that feature would be
necessary (bus connections etc) - it would get very messy and
duplicate much of what is already present in the mainline Linux device
tree's.  The above represents everything possible based on the
baseboard schematics and eeprom bit configuration but does not mean
all the combinations the above can result in are order-able boards.

>
> dts has the keyword "disabled", that let you enable or disable a
> specific feature. Maybe you could exchange the "status" field in dts
> instead of adding/dropping nodes.

I could do this but I'm not sure what is more appropriate.  I'll need
to inquire on the linux and device-tree mailing lists.

>
>> +}
>> +#endif /* defined(CONFIG_OF_FLAT_TREE) && defined(CONFIG_OF_BOARD_SETUP) */
>> +
>> diff --git a/board/gateworks/gw_ventana/gw_ventana.cfg b/board/gateworks/gw_ventana/gw_ventana.cfg
>> new file mode 100644
>> index 0000000..4e07528
>> --- /dev/null
>> +++ b/board/gateworks/gw_ventana/gw_ventana.cfg
>> @@ -0,0 +1,42 @@
>> +/*
>> + * Copyright (C) 2013 Gateworks Corporation
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + *
>> + * Refer doc/README.imximage for more details about how-to configure
>> + * and create imximage boot image
>> + *
>> + * The syntax is taken as close as possible with the kwbimage
>> + */
>> +
>> +/* image version */
>> +IMAGE_VERSION 2
>> +
>> +/*
>> + * Boot Device : one of
>> + * spi, sd, nand, sata
>> + */
>> +#ifdef CONFIG_SPI_FLASH
>> +BOOT_FROM      spi
>> +#else
>> +BOOT_FROM      nand
>> +#endif
>
> Do you boot also from SPI ?

The original prototype board for the Ventana family did (we only
produced and shipped a handful of these but there are still some in
the wild).  This is the config for gwventanaq1gspi config in
boards.cfg.

>
>> +
>> +#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 "ddr-setup.cfg"
>> +#if defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 1024
>> +  #include "1066mhz_4x128mx16.cfg"
>> +#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 1024
>> +  #include "800mhz_4x128mx16.cfg"
>> +#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 512
>> +  #include "800mhz_2x128mx16.cfg"
>> +#else
>> +  #error "Unsupported CPU/Memory configuration"
>> +#endif
>> +#include "clocks.cfg"
>> diff --git a/board/gateworks/gw_ventana/ventana_eeprom.h b/board/gateworks/gw_ventana/ventana_eeprom.h
>> new file mode 100644
>> index 0000000..ea6524a
>> --- /dev/null
>> +++ b/board/gateworks/gw_ventana/ventana_eeprom.h
>> @@ -0,0 +1,107 @@
>> +/*
>> + * ventana_eeprom.h - Gateworks Ventana EEPROM Configuration
>> + * v1.00
>> + */
>> +#ifndef _VENTANA_EEPROM_
>> +#define _VENTANA_EEPROM_
>> +
>> +struct ventana_board_info {
>> +     u8 mac0[6];          /* 0x00: MAC1 */
>> +     u8 mac1[6];          /* 0x06: MAC2 */
>> +     u8 res0[12];         /* 0x0C: reserved */
>> +     u32 serial;          /* 0x18: Serial Number (read only) */
>> +     u8 res1[4];          /* 0x1C: reserved */
>> +     u8 mfgdate[4];       /* 0x20: MFG date (read only) */
>> +     u8 res2[7];          /* 0x24 */
>> +     /* sdram config */
>> +     u8 sdram_size;       /* 0x2B: enum (512,1024,2048) MB */
>> +     u8 sdram_speed;      /* 0x2C: enum (100,133,166,200,267,333,400) MHz */
>> +     u8 sdram_width;      /* 0x2D: enum (32,64) bit */
>> +     /* cpu config */
>> +     u8 cpu_speed;        /* 0x2E: enum (800,1000,1200) MHz */
>> +     u8 cpu_type;         /* 0x2F: enum (imx6q,imx6d,imx6dl,imx6s) */
>> +     u8 model[16];        /* 0x30: model string */
>> +     /* FLASH config */
>> +     u8 nand_flash_size;  /* 0x40: enum (4,8,16,32,64,128) MB */
>> +     u8 spi_flash_size;   /* 0x41: enum (4,8,16,32,64,128) MB */
>> +
>> +     /* Config1: SoC Peripherals */
>> +     u8 config_eth0:1;    /* 0: 0x42 */
>> +     u8 config_eth1:1;    /* 1 */
>> +     u8 config_hdmi_out:1;/* 2 */
>> +     u8 config_sata:1;    /* 3 */
>> +     u8 config_pcie:1;    /* 4 */
>> +     u8 config_ssi0:1;    /* 5 */
>> +     u8 config_ssi1:1;    /* 6 */
>> +     u8 config_lcd:1;     /* 7 */
>
> Generally, using bitwise fields is deprecated in favour of using maks.
> This because there is no conventions how the compiler should assign (MSB
> or LSB) the single bits.

Can you point me to an example?  I'm not sure what you mean by 'maks'
(macros defining bit positions perhaps?).

>
>> +
>> +     u8 config_lvds0:1;   /* 0: 0x43 */
>> +     u8 config_lvds1:1;   /* 1 */
>> +     u8 config_usb0:1;    /* 2 (USB EHCI) */
>> +     u8 config_usb1:1;    /* 3 (USB OTG) */
>> +     u8 config_sd0:1;     /* 4 */
>> +     u8 config_sd1:1;     /* 5 */
>> +     u8 config_sd2:1;     /* 6 */
>> +     u8 config_sd3:1;     /* 7 */
>> +
>> +     u8 config_uart0:1;   /* 0: 0x44 */
>> +     u8 config_uart1:1;   /* 1 */
>> +     u8 config_uart2:1;   /* 2 */
>> +     u8 config_uart3:1;   /* 3 */
>> +     u8 config_uart4:1;   /* 4 */
>> +     u8 config_ipu0:1;    /* 5 */
>> +     u8 config_ipu1:1;    /* 6 */
>> +     u8 config_flexcan:1; /* 7 */
>> +
>> +     u8 config_mipi_dsi:1;/* 0: 0x45 */
>> +     u8 config_mipi_csi:1;/* 1 */
>> +     u8 config_tzasc0:1;  /* 2 */
>> +     u8 config_tzasc1:1;  /* 3 */
>> +     u8 config_i2c0:1;    /* 4 */
>> +     u8 config_i2c1:1;    /* 5 */
>> +     u8 config_i2c2:1;    /* 6 */
>> +     u8 config_vpu:1;     /* 7 */
>> +
>> +     u8 config_csi0:1;    /* 0: 0x46 */
>> +     u8 config_csi1:1;    /* 1 */
>> +     u8 config_caam:1;    /* 2 */
>> +     u8 config_mezz:1;    /* 3 */
>> +     u8 config_res1:1;    /* 4 */
>> +     u8 config_res2:1;    /* 5 */
>> +     u8 config_res3:1;    /* 6 */
>> +     u8 config_res4:1;    /* 7 */
>> +
>> +     u8 config_espci0:1;  /* 0: 0x47 */
>> +     u8 config_espci1:1;  /* 1 */
>> +     u8 config_espci2:1;  /* 2 */
>> +     u8 config_espci3:1;  /* 3 */
>> +     u8 config_espci4:1;  /* 4 */
>> +     u8 config_espci5:1;  /* 5 */
>> +     u8 config_res5:1;    /* 6 */
>> +     u8 config_res6:1;    /* 7 */
>> +
>> +     /* Config2: Other Peripherals */
>> +     u8 config_gps:1;     /* 0: 0x48 */
>> +     u8 config_spifl0:1;  /* 1 */
>> +     u8 config_spifl1:1;  /* 2 */
>> +     u8 config_gspbatt:1; /* 3 */
>> +     u8 config_hdmi_in:1; /* 4 */
>> +     u8 config_vid_out:1; /* 5 */
>> +     u8 config_vid_in:1;  /* 6 */
>> +     u8 config_nand:1;    /* 7 */
>> +
>> +     u8 config_res8:1;    /* 0: 0x49 */
>> +     u8 config_res9:1;    /* 1 */
>> +     u8 config_res10:1;   /* 2 */
>> +     u8 config_res11:1;   /* 3 */
>> +     u8 config_res12:1;   /* 4 */
>> +     u8 config_res13:1;   /* 5 */
>> +     u8 config_res14:1;   /* 6 */
>> +     u8 config_res15:1;   /* 7 */
>> +
>> +     u8 res3[4];          /* 0x4A */
>> +
>> +     u8 chksum[2];        /* 0x4E */
>> +};
>> +
>> +#endif
>> diff --git a/boards.cfg b/boards.cfg
>> index a8336cc..7784b3a 100644
>> --- a/boards.cfg
>> +++ b/boards.cfg
>> @@ -295,6 +295,7 @@ Active  arm         armv7          mx6         -               udoo                  udoo_qua
>>  Active  arm         armv7          mx6         -               wandboard           wandboard_dl                         wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024                                                  Fabio Estevam <fabio.estevam@freescale.com>
>>  Active  arm         armv7          mx6         -               wandboard           wandboard_quad                       wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q2g.cfg,MX6Q,DDR_MB=2048                                                  Fabio Estevam <fabio.estevam@freescale.com>
>>  Active  arm         armv7          mx6         -               wandboard           wandboard_solo                       wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6s.cfg,MX6S,DDR_MB=512                                                     Fabio Estevam <fabio.estevam@freescale.com>
>> +Active  arm         armv7          mx6         barco           titanium            titanium                             titanium:IMX_CONFIG=board/barco/titanium/imximage.cfg                                                                         Stefan Roese <sr@denx.de>
>
> Why do you touch the titanium ?

it wasn't in alphabetical order (barco should be before boundary).  I
will not touch it as that shouldn't be part of my patch.

>
>>  Active  arm         armv7          mx6         boundary        nitrogen6x          mx6qsabrelite                        nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q.cfg,MX6Q,DDR_MB=1024,SABRELITE                                         Eric Nelson <eric.nelson@boundarydevices.com>
>>  Active  arm         armv7          mx6         boundary        nitrogen6x          nitrogen6dl                          nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024                                                 Eric Nelson <eric.nelson@boundarydevices.com>
>>  Active  arm         armv7          mx6         boundary        nitrogen6x          nitrogen6dl2g                        nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl2g.cfg,MX6DL,DDR_MB=2048                                               Eric Nelson <eric.nelson@boundarydevices.com>
>> @@ -308,7 +309,11 @@ 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         barco           titanium            titanium                             titanium:IMX_CONFIG=board/barco/titanium/imximage.cfg                                                                         Stefan Roese <sr@denx.de>
>> +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>
>
> Please let the list sorted.

will do - I failed to sort the new additions with respect to each other.

Incidentally, I noticed that there are quite a few lines out of order
from what tools/reformat.py does.

Thanks again for the review!  I hope to have a v2 ready in perhaps a week.

Tim

>
> 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
> =====================================================================
Stefano Babic Jan. 28, 2014, 10:20 a.m. UTC | #5
Hi Tim,

On 28/01/2014 00:36, Tim Harvey wrote:

> 
> I will include the ddr config files from boundary with a
> ../../boundary/... where they do not differ.  The clocks.cfg does
> differ (see below) but I liked the way Boundary broke these files out
> do want to re-use as much as possible.

ok, I see. Clock for NAND is not enabled in nitrogen's file. Well, then
we should have only clocks.cfg for ventana.

>>> diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README
>>> new file mode 100644
>>> index 0000000..9de55ba
>>> --- /dev/null
>>> +++ b/board/gateworks/gw_ventana/README
>>> @@ -0,0 +1,49 @@
>>> +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
>>> +------------------------------
>>> +
>>> +The i.MX6 BOOT ROM expects some headers 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.
>>
>> The behavior is quite different as we have currently in mainline. With
>> kobs-ng you flash u-boot.bin, while the result image for i.MXes in
>> mailine is u-boot.imx (u-boot.bin with imx header).
> 
> I'm not familiar with the IMX family other than IMX6 but for IMX6
> kobs-ng does use u-boot.imx and not u-boot.bin.  kobs needs the
> headers which are not part of u-boot.bin.  Are you sure you are not
> mistaken here?  Can you point me to some references?

I think there is a misunderstanding due to the usage of "headers". What
do you mean with headers here ? As you talk about BOOT ROM, the only
header that the ROM understands is the i.MX image header, that is the
description of the image itself with the DCD and all that stuff. When
you say that kobs-ng needs "headers", it seems you are talking about .h
files,

As far as I know, kobs-ng is a flasher - a utility to install u-boot on
the target. It is not the only method to install the binary. I think you
should rework the text making the statements more clearer.

> Regardless of what is loading the next level (u-boot.bin) the initial
> flashing of NAND is still currently handled only by kobs-ng so I'm not
> sure how this differs in this respect.  I plan to look at adding the
> functionality of kobs-ng to u-boot at some point.

If as I think kobs-ng is only a flasher, it does not take part to the
build of U-Boot binaries. IMHO it should be not part of U-Boot sources,
but maybe there are some features that can be interesting.

>>> + * retries.
>>> + */
>>> +int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
>>> +{
>>> +     int retry = 3;
>>> +     int n = 0;
>>> +     int ret;
>>> +
>>> +     while (n++ < retry) {
>>> +             ret = i2c_read(chip, addr, alen, buf, len);
>>> +             if (!ret)
>>> +                     break;
>>> +             printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
>>> +                    n, ret);
>>> +             if (ret != -ENODEV)
>>> +                     break;
>>> +             mdelay(10);
>>> +     }
>>
>> Whcih is the benefit of trying three times ?
> 
> it provides a little more redundancy than 2 times, and a little less than 4 ;)

As there is no guarantee that works, but it is only statistics, it looks
more a workaround as a solution.

> 
> Our GSC can occasionally be 'busy' and NAK (every 1Hz it does some
> internal processing).

ok - but is there no way to understand that the component is busy ?

I mean, in most hardware solutions (there is plenty of them in
Freescale's SOCs), software must poll a bit (a pin, whatever...) to
check if it can access the component. Nothing here ?

>  As there are several places where I perform an
> i2c transaction to one of the GSC's slave devices (it emulates several
> i2c devices) I wanted to consolidate where I had retry logic.  There
> is nothing magic about 3 tries necessarily but I have found that with
> the speed of the SoC we never fail more than 2 successive reads due to
> the periodic loading of the GSC.
> 
> If you want more info on the GSC you can read about it here:
> http://trac.gateworks.com/wiki/gsc

I read the doc - however, there is no mention about this important detail !

>>
>>> +
>>> +/*
>>> + * For SPL boot some boards need i2c before SDRAM is initialized so force
>>> + * variables to live in SRAM
>>> + */
>>
>> Agree - but then I will see SPL...
>>
>>> +static struct ventana_board_info __attribute__((section(".data"))) ventana_info;
>>
>> Can you explain why do you need this ?
> 
> This was in preparation for SPL.  I'm not clear if the struct needs
> any special attributes at this time to be available to all the
> functions that use it.  Because currently the BOOTROM sets up DDR I'm
> thinking perhaps not, but I seem to recall before I added the
> attribute I ran into some issues.

If it is at the moment dead code, please remove. Dead code that passes a
review will only confuse people.

>>> + * should be called once, the first time eeprom data is needed
>>> + */
>>> +static void
>>> +read_eeprom(void)
>>> +{
>>
>> You have a I2C eprom. This is supported in U-Boot. Why do you not
>> set CONFIG_SYS_I2C_EEPROM_ADDR in your config file and use general code ?
>>
>> It seems to me you can drop your own read/write_eeprom() function.
> 
> I considered this before (using common/cmd_eeprom.c), but the fact
> that I want to be able to handle retries on NAK's would keep me from
> using a generic read_eeprom feature.  Also, that common support only
> just replaces my gsc_i2c_read function -

Right, this is what I said with "payload". You have two functions:
- read from hardware
- check and interprete the result

The function that chjeck the data calls the function to read the data.

> inside read_eeprom I verify
> checksum and some other sanity checks.

As I said, you can check outside this function.

>  Grepping for
> CONFIG_SYS_I2C_EEPROM_ADDR there are a lot of boards that implement
> their own read_eeprom functionality for one reason or another.

Right. But again, if this is not strictly necessary, it is always better
to reuse common code. You can also check 3 times the result of
read_eeprom() to implement your retry-on-NAK, without implementing your
own version.

> 
>>
>>> +#ifdef CONFIG_CMD_GSC
>>> +int read_hwmon(const char *name, uint reg, uint size, uint low, uint high)
>>> +{
>>> +     unsigned char buf[3];
>>> +     uint ui;
>>> +     int ret;
>>> +
>>> +     printf("%-8s:", name);
>>> +     memset(buf, 0, sizeof(buf));
>>> +     if (gsc_i2c_read(0x29, reg, 1, buf, size)) {
>>> +             printf("fRD\n");
>>> +             ret = -1;
>>> +     } else {
>>> +             ret = 0;
>>> +             ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
>>> +             if (ui == 0xffffff) {
>>> +                     printf("fVL");
>>> +             } else if (ui < low) {
>>> +                     printf("%d fLO", ui);
>>> +                     ret = -2;
>>> +             } else if (ui > high) {
>>> +                     printf("%d fHI", ui);
>>> +                     ret = -3;
>>> +             } else {
>>> +                     printf("%d", ui);
>>> +             }
>>> +     }
>>> +     printf("\n");
>>> +
>>> +     return ret;
>>> +}
>>
>> I need help - I have not understood. This functions prints only
>> something - return values is discarded when function is called. Buf is
>> filled, but can you better explain the purpose of the function.
> 
> The gsc command (below) is currently just showing the values from the
> hardware monitor (temp and various voltage rails).  The read_hwmon
> function above is a helper function to display the value, or a failure
> high, or failure low in a standard fashion.

ok - then this is only a function that outputs details about hardwrae. Then:
- function must be declared static
- why should the function return a int if it is not checked at all ?

>>> +#endif
>>> +     gpio_direction_output(IMX_GPIO_NR(3, 22), 0); /* OTG power off */
>>> +
>>> +     /* Note this gets called again later,
>>> +      * but needed in case i2c bus is stuck */
>>> +     timer_init();
>>
>> timer_init() ? I think this is called by generic code.
> 
> it is, but as the common states its called later (at least it was when
> I first wrote this) and causes one of the error handling functions to
> hang when it tries to delay. 

This is correct. udelay() at this point is not yet working.
board_early_init_f() is thought to set up hardware that is required
before relocation. At this point, generally clocks and pinmuxes setup
take place. The rest should be postponed to a later point, that is,
board_init, or even board_late_init() (if you activate it) or misc_init().


> The specific issue I was working around
> here had to do with no console output from the bootloader if you had
> for example an HDMI monitor plugged in with a bad EDID clk/data pin.

You do not need HDMI before relocation.


>> General remak: you print a lot of stuff by booting. This can slow down
>> your boot process significantly adding several seconds to your start up,
>> before the kernel is loaded.
> 
> agreed - perhaps there are some common defines I can use to quiet
> things down by default or even better an env variable that the user
> can set?
> 
> We've found that showing the boot device, and model in the bootloader
> is extremely helpfull in supporting users but I suppose I could move
> some of the other things like DIO/SATA/RS232 configuration (hwconfig
> controlled) reporting to a user command.

You are mixing two things. During the boot process, it is better to
print only what is really needed to speed up the process. The user has
maybe no access to the console, and he wants that the system reacts very
soon - with kernel, application, everything.

If a user is operating at U-Boot console, he has all the time he wants.
Some output can be displayed with an additional command.

See "clocks" command for i.MXes - clock configuration is printed only on
demand.


>>
>> Generally, using bitwise fields is deprecated in favour of using maks.
>> This because there is no conventions how the compiler should assign (MSB
>> or LSB) the single bits.
> 
> Can you point me to an example?  I'm not sure what you mean by 'maks'
> (macros defining bit positions perhaps?).

I need to buy a new keyboard - "s" key is not working well. It is not
"maks", but "masks". Yes, accessing bit with and and or logical
operation. And using the provided helper functions (clrsetbits_).

Best regards,
Stefano Babic
Tim Harvey Jan. 29, 2014, 1:26 a.m. UTC | #6
On Tue, Jan 28, 2014 at 2:20 AM, Stefano Babic <sbabic@denx.de> wrote:
> Hi Tim,
>
> On 28/01/2014 00:36, Tim Harvey wrote:
>
<snip>
>>>> diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README
>>>> new file mode 100644
>>>> index 0000000..9de55ba
>>>> --- /dev/null
>>>> +++ b/board/gateworks/gw_ventana/README
>>>> @@ -0,0 +1,49 @@
>>>> +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
>>>> +------------------------------
>>>> +
>>>> +The i.MX6 BOOT ROM expects some headers 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.
>>>
>>> The behavior is quite different as we have currently in mainline. With
>>> kobs-ng you flash u-boot.bin, while the result image for i.MXes in
>>> mailine is u-boot.imx (u-boot.bin with imx header).
>>
>> I'm not familiar with the IMX family other than IMX6 but for IMX6
>> kobs-ng does use u-boot.imx and not u-boot.bin.  kobs needs the
>> headers which are not part of u-boot.bin.  Are you sure you are not
>> mistaken here?  Can you point me to some references?
>
> I think there is a misunderstanding due to the usage of "headers". What
> do you mean with headers here ? As you talk about BOOT ROM, the only
> header that the ROM understands is the i.MX image header, that is the
> description of the image itself with the DCD and all that stuff. When
> you say that kobs-ng needs "headers", it seems you are talking about .h
> files,

I should not have used the word 'header'.

I _am_ talking about the Image Vector Table (IVT) and Device
Configuration Data (DCD) data structures that the IMX6 BOOT ROM needs
to boot and which are present in u-boot.imx.  The kobs-ng (at least
for IMX6) needs u-boot.imx because it contains these structures built
from imximage and it must flash them onto the boot media.

>
> As far as I know, kobs-ng is a flasher - a utility to install u-boot on
> the target. It is not the only method to install the binary. I think you
> should rework the text making the statements more clearer.

Can you re-read the README instructions?  Other than the bad link I
feel they are very clear.  I think perhaps your thinking that I was in
error specifying that kobs-ng needing u-boot.imx added to some
confusion?

>
>> Regardless of what is loading the next level (u-boot.bin) the initial
>> flashing of NAND is still currently handled only by kobs-ng so I'm not
>> sure how this differs in this respect.  I plan to look at adding the
>> functionality of kobs-ng to u-boot at some point.
>
> If as I think kobs-ng is only a flasher, it does not take part to the
> build of U-Boot binaries. IMHO it should be not part of U-Boot sources,
> but maybe there are some features that can be interesting.
>

I was not referring to making the code a part of uboot sources but
adding the functionality that it provides such that one could use
uboot to update itself on an IMX NAND device.  I'm actually surprised
nobody has done this before for IMX in general as its a bit
inconvenient to boot to a linux based OS in order to run kobs-ng to
flash the bootloader.  Regardless, this would be functionality added
later.

It appears the only other mainlined IMX6 bootloader to support NAND is
the Titanium and there is no README for it at all.  If there were, I
would expect it to say pretty much the same thing that my proposed
Ventana README states.  There was a comment by Fabio on original
titanium patch to include a README explaining how to flash and boot
from NAND but it apparently didn't make it in:
http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/158436/focus=158441

I've added Stefan Roese and Fabio to the cc to hear their thoughts.

>>>> + * retries.
>>>> + */
>>>> +int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
>>>> +{
>>>> +     int retry = 3;
>>>> +     int n = 0;
>>>> +     int ret;
>>>> +
>>>> +     while (n++ < retry) {
>>>> +             ret = i2c_read(chip, addr, alen, buf, len);
>>>> +             if (!ret)
>>>> +                     break;
>>>> +             printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
>>>> +                    n, ret);
>>>> +             if (ret != -ENODEV)
>>>> +                     break;
>>>> +             mdelay(10);
>>>> +     }
>>>
>>> Whcih is the benefit of trying three times ?
>>
>> it provides a little more redundancy than 2 times, and a little less than 4 ;)
>
> As there is no guarantee that works, but it is only statistics, it looks
> more a workaround as a solution.
>
>>
>> Our GSC can occasionally be 'busy' and NAK (every 1Hz it does some
>> internal processing).
>
> ok - but is there no way to understand that the component is busy ?

No - the only communication channel to the GSC is the i2c bus.  The
only way it has to respond is to ACK or fail to ACK (aka NAK) within
the i2c bit time (aka NAK).  The device does not and can not support
i2c clock stretching.  The nature of GSC is such that the worst case
failure when talking at 100kbps will be at most 2 times in a row (due
to the latency of the timer tick) which is why I have a retry of 3.

>
> I mean, in most hardware solutions (there is plenty of them in
> Freescale's SOCs), software must poll a bit (a pin, whatever...) to
> check if it can access the component. Nothing here ?

no - this is a 'slave' device on the i2c bus that is too busy to
respond in the allotted time, not the controller.  This isn't unheard
of.  Some i2c based EEPROM's need a certain delay after writing for
example, before they are ready again for reading.

I 'can' as you say call the common i2c_read and wrap that around 3
retries but I don't any better solution to the other i2c read/writes
to the GSC such as reading the hwmon, RTC, or firmware registers with
up to 3 retries so it really doesn't shorten the code any.  Note that
I am using common i2c_read.  I don't really see any benefit to using
the common eeprom_read over the common i2c_read as I know I'm not
wrapping page boundaries.

Would you rather see me implement retries down at the i2c_core level
or at the i2c driver level?

>
>>  As there are several places where I perform an
>> i2c transaction to one of the GSC's slave devices (it emulates several
>> i2c devices) I wanted to consolidate where I had retry logic.  There
>> is nothing magic about 3 tries necessarily but I have found that with
>> the speed of the SoC we never fail more than 2 successive reads due to
>> the periodic loading of the GSC.
>>
>> If you want more info on the GSC you can read about it here:
>> http://trac.gateworks.com/wiki/gsc
>
> I read the doc - however, there is no mention about this important detail !

fair enough - I have updated the wiki page to make this clear.

>
>>>
>>>> +
>>>> +/*
>>>> + * For SPL boot some boards need i2c before SDRAM is initialized so force
>>>> + * variables to live in SRAM
>>>> + */
>>>
>>> Agree - but then I will see SPL...
>>>
>>>> +static struct ventana_board_info __attribute__((section(".data"))) ventana_info;
>>>
>>> Can you explain why do you need this ?
>>
>> This was in preparation for SPL.  I'm not clear if the struct needs
>> any special attributes at this time to be available to all the
>> functions that use it.  Because currently the BOOTROM sets up DDR I'm
>> thinking perhaps not, but I seem to recall before I added the
>> attribute I ran into some issues.
>
> If it is at the moment dead code, please remove. Dead code that passes a
> review will only confuse people.

once I realized I could #define CONFIG_DISPLAY_BOARDINFO_LATE to make
checkconfig() run after relocation I no longer needed to have EEPROM
read prior to relocation and that removed the need for this structure
to be in the data segement.  I still have the structure so that eeprom
can be read just once (as its used in several places) but it no longer
needs to be in the data segment so the attribute will be removed in
the next patch version.

>
>>>> + * should be called once, the first time eeprom data is needed
>>>> + */
>>>> +static void
>>>> +read_eeprom(void)
>>>> +{
>>>
>>> You have a I2C eprom. This is supported in U-Boot. Why do you not
>>> set CONFIG_SYS_I2C_EEPROM_ADDR in your config file and use general code ?
>>>
>>> It seems to me you can drop your own read/write_eeprom() function.
>>
>> I considered this before (using common/cmd_eeprom.c), but the fact
>> that I want to be able to handle retries on NAK's would keep me from
>> using a generic read_eeprom feature.  Also, that common support only
>> just replaces my gsc_i2c_read function -
>
> Right, this is what I said with "payload". You have two functions:
> - read from hardware
> - check and interprete the result
>
> The function that chjeck the data calls the function to read the data.
>
>> inside read_eeprom I verify
>> checksum and some other sanity checks.
>
> As I said, you can check outside this function.

sure... but understand the only 'extra' code here is the
implementation of gsc_i2c_read and gsc_i2c_write which wrap the common
i2c_read/i2c_write functions around a retry of 3.   If I were to use
common i2c_read or eeprom_read I'm only substituting the call to
gsc_i2c_read.

>
>>  Grepping for
>> CONFIG_SYS_I2C_EEPROM_ADDR there are a lot of boards that implement
>> their own read_eeprom functionality for one reason or another.
>
> Right. But again, if this is not strictly necessary, it is always better
> to reuse common code. You can also check 3 times the result of
> read_eeprom() to implement your retry-on-NAK, without implementing your
> own version.
>

Yes - I could, but then I wouldn't have a solution for the calls that
read the other device registers that the GSC emulates (which are at
different slave addresses).

>>
>>>
>>>> +#ifdef CONFIG_CMD_GSC
>>>> +int read_hwmon(const char *name, uint reg, uint size, uint low, uint high)
>>>> +{
>>>> +     unsigned char buf[3];
>>>> +     uint ui;
>>>> +     int ret;
>>>> +
>>>> +     printf("%-8s:", name);
>>>> +     memset(buf, 0, sizeof(buf));
>>>> +     if (gsc_i2c_read(0x29, reg, 1, buf, size)) {
>>>> +             printf("fRD\n");
>>>> +             ret = -1;
>>>> +     } else {
>>>> +             ret = 0;
>>>> +             ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
>>>> +             if (ui == 0xffffff) {
>>>> +                     printf("fVL");
>>>> +             } else if (ui < low) {
>>>> +                     printf("%d fLO", ui);
>>>> +                     ret = -2;
>>>> +             } else if (ui > high) {
>>>> +                     printf("%d fHI", ui);
>>>> +                     ret = -3;
>>>> +             } else {
>>>> +                     printf("%d", ui);
>>>> +             }
>>>> +     }
>>>> +     printf("\n");
>>>> +
>>>> +     return ret;
>>>> +}
>>>
>>> I need help - I have not understood. This functions prints only
>>> something - return values is discarded when function is called. Buf is
>>> filled, but can you better explain the purpose of the function.
>>
>> The gsc command (below) is currently just showing the values from the
>> hardware monitor (temp and various voltage rails).  The read_hwmon
>> function above is a helper function to display the value, or a failure
>> high, or failure low in a standard fashion.
>
> ok - then this is only a function that outputs details about hardwrae. Then:
> - function must be declared static
> - why should the function return a int if it is not checked at all ?

Its both displaying the value and evaluating the value for pass, fail
(high) and fail (low).  As those return codes are not used, I'll
remove the return value.

>
>>>> +#endif
>>>> +     gpio_direction_output(IMX_GPIO_NR(3, 22), 0); /* OTG power off */
>>>> +
>>>> +     /* Note this gets called again later,
>>>> +      * but needed in case i2c bus is stuck */
>>>> +     timer_init();
>>>
>>> timer_init() ? I think this is called by generic code.
>>
>> it is, but as the common states its called later (at least it was when
>> I first wrote this) and causes one of the error handling functions to
>> hang when it tries to delay.
>
> This is correct. udelay() at this point is not yet working.
> board_early_init_f() is thought to set up hardware that is required
> before relocation. At this point, generally clocks and pinmuxes setup
> take place. The rest should be postponed to a later point, that is,
> board_init, or even board_late_init() (if you activate it) or misc_init().
>

got it - moving checkboard() to late init resolved this.

>
>> The specific issue I was working around
>> here had to do with no console output from the bootloader if you had
>> for example an HDMI monitor plugged in with a bad EDID clk/data pin.
>
> You do not need HDMI before relocation.
>

agreed - will be fixed

>
>>> General remak: you print a lot of stuff by booting. This can slow down
>>> your boot process significantly adding several seconds to your start up,
>>> before the kernel is loaded.
>>
>> agreed - perhaps there are some common defines I can use to quiet
>> things down by default or even better an env variable that the user
>> can set?
>>
>> We've found that showing the boot device, and model in the bootloader
>> is extremely helpfull in supporting users but I suppose I could move
>> some of the other things like DIO/SATA/RS232 configuration (hwconfig
>> controlled) reporting to a user command.
>
> You are mixing two things. During the boot process, it is better to
> print only what is really needed to speed up the process. The user has
> maybe no access to the console, and he wants that the system reacts very
> soon - with kernel, application, everything.
>
> If a user is operating at U-Boot console, he has all the time he wants.
> Some output can be displayed with an additional command.
>
> See "clocks" command for i.MXes - clock configuration is printed only on
> demand.
>

agreed - I will move most of this into user commands.

>
>>>
>>> Generally, using bitwise fields is deprecated in favour of using maks.
>>> This because there is no conventions how the compiler should assign (MSB
>>> or LSB) the single bits.
>>
>> Can you point me to an example?  I'm not sure what you mean by 'maks'
>> (macros defining bit positions perhaps?).
>
> I need to buy a new keyboard - "s" key is not working well. It is not
> "maks", but "masks". Yes, accessing bit with and and or logical
> operation. And using the provided helper functions (clrsetbits_).

I'll for sure take a stab at this - I've been wanting to re-define
that structure using macros for a while anyway.

Thanks,

Tim

>
> 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
> =====================================================================
Stefan Roese Jan. 29, 2014, 7:07 a.m. UTC | #7
Hi Tim,

On 29.01.2014 02:26, Tim Harvey wrote:
>>> Regardless of what is loading the next level (u-boot.bin) the initial
>>> flashing of NAND is still currently handled only by kobs-ng so I'm not
>>> sure how this differs in this respect.  I plan to look at adding the
>>> functionality of kobs-ng to u-boot at some point.
>>
>> If as I think kobs-ng is only a flasher, it does not take part to the
>> build of U-Boot binaries. IMHO it should be not part of U-Boot sources,
>> but maybe there are some features that can be interesting.
>>
>
> I was not referring to making the code a part of uboot sources but
> adding the functionality that it provides such that one could use
> uboot to update itself on an IMX NAND device.  I'm actually surprised
> nobody has done this before for IMX in general as its a bit
> inconvenient to boot to a linux based OS in order to run kobs-ng to
> flash the bootloader.  Regardless, this would be functionality added
> later.

That would be really convenient. Not having to boot Linux and to rely on 
kobs-ng for flashing U-Boot for NAND booting imx6.

> It appears the only other mainlined IMX6 bootloader to support NAND is
> the Titanium and there is no README for it at all.  If there were, I
> would expect it to say pretty much the same thing that my proposed
> Ventana README states.  There was a comment by Fabio on original
> titanium patch to include a README explaining how to flash and boot
> from NAND but it apparently didn't make it in:
> http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/158436/focus=158441
>
> I've added Stefan Roese and Fabio to the cc to hear their thoughts.

Yes, your README seems correct to me. So for this README:

Reviewed-by: Stefan Roese <sr@denx.de>

Thanks,
Stefan
Stefano Babic Jan. 29, 2014, 8:19 a.m. UTC | #8
Hi Tim,

On 29/01/2014 02:26, Tim Harvey wrote:

> 
> I should not have used the word 'header'.
> 
> I _am_ talking about the Image Vector Table (IVT) and Device
> Configuration Data (DCD) data structures that the IMX6 BOOT ROM needs
> to boot and which are present in u-boot.imx.

Right.

>  The kobs-ng (at least
> for IMX6) needs u-boot.imx because it contains these structures built
> from imximage and it must flash them onto the boot media.

ok, got it. My suggestion is then only to headline that kons-ng uses a
imximage, that contains IVT and DCD.

> 
>>
>> As far as I know, kobs-ng is a flasher - a utility to install u-boot on
>> the target. It is not the only method to install the binary. I think you
>> should rework the text making the statements more clearer.
> 
> Can you re-read the README instructions?  Other than the bad link I
> feel they are very clear.  I think perhaps your thinking that I was in
> error specifying that kobs-ng needing u-boot.imx added to some
> confusion?

Yes, it had confused me. IMHO you could add that kobs-ng adds the FCB
structure that it is not (yet) provided by imximage.

>>
>> If as I think kobs-ng is only a flasher, it does not take part to the
>> build of U-Boot binaries. IMHO it should be not part of U-Boot sources,
>> but maybe there are some features that can be interesting.
>>
> 
> I was not referring to making the code a part of uboot sources but
> adding the functionality that it provides such that one could use
> uboot to update itself on an IMX NAND device.  I'm actually surprised
> nobody has done this before for IMX in general as its a bit
> inconvenient to boot to a linux based OS in order to run kobs-ng to
> flash the bootloader.
>  Regardless, this would be functionality added
> later.

It would be great. Of course, it will be great if we can flash NAND
exactly as we do for other SOCs. We will need to improve imximage to add
the FCB at the beginning of the image.

> 
> It appears the only other mainlined IMX6 bootloader to support NAND is
> the Titanium and there is no README for it at all.  If there were, I
> would expect it to say pretty much the same thing that my proposed
> Ventana README states.  There was a comment by Fabio on original
> titanium patch to include a README explaining how to flash and boot
> from NAND but it apparently didn't make it in:
> http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/158436/focus=158441

Good point. Stefan, how do you flash the titanium ? At the moment I do
not see any other way as using the kobs-ng. Or do you have some early
improvement for mkimage adding the FCB/DBBT data ?

> 
> No - the only communication channel to the GSC is the i2c bus.  The
> only way it has to respond is to ACK or fail to ACK (aka NAK) within
> the i2c bit time (aka NAK).  The device does not and can not support
> i2c clock stretching.  The nature of GSC is such that the worst case
> failure when talking at 100kbps will be at most 2 times in a row (due
> to the latency of the timer tick) which is why I have a retry of 3.

ok - I think it will be cleaner if you split your patch and move gsc
code in a separate file, still in your board directory. I understand the
point - if the hardware does not provide any way to check if it is busy,
it is ok to retry when first access fails.

>> If it is at the moment dead code, please remove. Dead code that passes a
>> review will only confuse people.
> 
> once I realized I could #define CONFIG_DISPLAY_BOARDINFO_LATE to make
> checkconfig() run after relocation I no longer needed to have EEPROM
> read prior to relocation and that removed the need for this structure
> to be in the data segement.  I still have the structure so that eeprom
> can be read just once (as its used in several places) but it no longer
> needs to be in the data segment so the attribute will be removed in
> the next patch version.

Fine.

Best regards,
Stefano Babic
Stefan Roese Jan. 29, 2014, 8:36 a.m. UTC | #9
Hi Stefano,

On 29.01.2014 09:19, Stefano Babic wrote:
>> It appears the only other mainlined IMX6 bootloader to support NAND is
>> the Titanium and there is no README for it at all.  If there were, I
>> would expect it to say pretty much the same thing that my proposed
>> Ventana README states.  There was a comment by Fabio on original
>> titanium patch to include a README explaining how to flash and boot
>> from NAND but it apparently didn't make it in:
>> http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/158436/focus=158441
>
> Good point. Stefan, how do you flash the titanium ? At the moment I do
> not see any other way as using the kobs-ng. Or do you have some early
> improvement for mkimage adding the FCB/DBBT data ?

No. As already mentioned in my previous mail, I also used kobs-ng via 
Linux to flash the NAND booting image.

Thanks,
Stefan
diff mbox

Patch

diff --git a/board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg b/board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg
new file mode 100644
index 0000000..6c68146
--- /dev/null
+++ b/board/gateworks/gw_ventana/1066mhz_4x128mx16.cfg
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright (C) 2013 Boundary Devices
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+DATA 4, MX6_MMDC_P0_MDPDC, 0x00020036
+DATA 4, MX6_MMDC_P0_MDCFG0, 0x555A7974
+DATA 4, MX6_MMDC_P0_MDCFG1, 0xDB538F64
+DATA 4, MX6_MMDC_P0_MDCFG2, 0x01FF00DB
+DATA 4, MX6_MMDC_P0_MDRWD, 0x000026D2
+DATA 4, MX6_MMDC_P0_MDOR, 0x005A1023
+DATA 4, MX6_MMDC_P0_MDOTC, 0x09444040
+DATA 4, MX6_MMDC_P0_MDPDC, 0x00025576
+DATA 4, MX6_MMDC_P0_MDASP, 0x00000027
+DATA 4, MX6_MMDC_P0_MDCTL, 0x831A0000
+DATA 4, MX6_MMDC_P0_MDSCR, 0x04088032
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00008033
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00428031
+DATA 4, MX6_MMDC_P0_MDSCR, 0x19308030
+DATA 4, MX6_MMDC_P0_MDSCR, 0x04008040
+DATA 4, MX6_MMDC_P0_MPZQHWCTRL, 0xA1390003
+DATA 4, MX6_MMDC_P1_MPZQHWCTRL, 0xA1390003
+DATA 4, MX6_MMDC_P0_MDREF, 0x00005800
+DATA 4, MX6_MMDC_P0_MPODTCTRL, 0x00022227
+DATA 4, MX6_MMDC_P1_MPODTCTRL, 0x00022227
+DATA 4, MX6_MMDC_P0_MPDGCTRL0, 0x42720306
+DATA 4, MX6_MMDC_P0_MPDGCTRL1, 0x026F0266
+DATA 4, MX6_MMDC_P1_MPDGCTRL0, 0x4273030A
+DATA 4, MX6_MMDC_P1_MPDGCTRL1, 0x02740240
+DATA 4, MX6_MMDC_P0_MPRDDLCTL, 0x45393B3E
+DATA 4, MX6_MMDC_P1_MPRDDLCTL, 0x403A3747
+DATA 4, MX6_MMDC_P0_MPWRDLCTL, 0x40434541
+DATA 4, MX6_MMDC_P1_MPWRDLCTL, 0x473E4A3B
+DATA 4, MX6_MMDC_P0_MPWLDECTRL0, 0x0011000E
+DATA 4, MX6_MMDC_P0_MPWLDECTRL1, 0x000E001B
+DATA 4, MX6_MMDC_P1_MPWLDECTRL0, 0x00190015
+DATA 4, MX6_MMDC_P1_MPWLDECTRL1, 0x00070018
+DATA 4, MX6_MMDC_P0_MPMUR0, 0x00000800
+DATA 4, MX6_MMDC_P1_MPMUR0, 0x00000800
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00000000
+DATA 4, MX6_MMDC_P0_MAPSR, 0x00011006
diff --git a/board/gateworks/gw_ventana/800mhz_2x128mx16.cfg b/board/gateworks/gw_ventana/800mhz_2x128mx16.cfg
new file mode 100644
index 0000000..e005a64
--- /dev/null
+++ b/board/gateworks/gw_ventana/800mhz_2x128mx16.cfg
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright (C) 2013 Boundary Devices
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+DATA 4, MX6_MMDC_P0_MDPDC, 0x0002002D
+DATA 4, MX6_MMDC_P0_MDCFG0, 0x40435323
+DATA 4, MX6_MMDC_P0_MDCFG1, 0xB66E8D63
+DATA 4, MX6_MMDC_P0_MDCFG2, 0x01FF00DB
+DATA 4, MX6_MMDC_P0_MDRWD, 0x000026D2
+DATA 4, MX6_MMDC_P0_MDOR, 0x00431023
+DATA 4, MX6_MMDC_P0_MDOTC, 0x00333030
+DATA 4, MX6_MMDC_P0_MDPDC, 0x0002556D
+DATA 4, MX6_MMDC_P0_MDASP, 0x00000017
+DATA 4, MX6_MMDC_P0_MDCTL, 0x83190000
+DATA 4, MX6_MMDC_P0_MDSCR, 0x04008032
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00008033
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00048031
+DATA 4, MX6_MMDC_P0_MDSCR, 0x13208030
+DATA 4, MX6_MMDC_P0_MDSCR, 0x04008040
+DATA 4, MX6_MMDC_P0_MPZQHWCTRL, 0xA1390003
+DATA 4, MX6_MMDC_P1_MPZQHWCTRL, 0xA1390003
+DATA 4, MX6_MMDC_P0_MDREF, 0x00005800
+DATA 4, MX6_MMDC_P0_MPODTCTRL, 0x00022227
+DATA 4, MX6_MMDC_P1_MPODTCTRL, 0x00022227
+DATA 4, MX6_MMDC_P0_MPDGCTRL0, 0x42350231
+DATA 4, MX6_MMDC_P1_MPDGCTRL0, 0x42350231
+DATA 4, MX6_MMDC_P0_MPDGCTRL1, 0x021A0218
+DATA 4, MX6_MMDC_P1_MPDGCTRL1, 0x021A0218
+DATA 4, MX6_MMDC_P0_MPRDDLCTL, 0x4B4B4E49
+DATA 4, MX6_MMDC_P1_MPRDDLCTL, 0x4B4B4E49
+DATA 4, MX6_MMDC_P0_MPWRDLCTL, 0x3F3F3035
+DATA 4, MX6_MMDC_P1_MPWRDLCTL, 0x3F3F3035
+DATA 4, MX6_MMDC_P0_MPWLDECTRL0, 0x0040003C
+DATA 4, MX6_MMDC_P0_MPWLDECTRL1, 0x0032003E
+DATA 4, MX6_MMDC_P1_MPWLDECTRL0, 0x0040003C
+DATA 4, MX6_MMDC_P1_MPWLDECTRL1, 0x0032003E
+DATA 4, MX6_MMDC_P0_MPMUR0, 0x00000800
+DATA 4, MX6_MMDC_P1_MPMUR0, 0x00000800
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00000000
+DATA 4, MX6_MMDC_P0_MAPSR, 0x00011006
diff --git a/board/gateworks/gw_ventana/800mhz_4x128mx16.cfg b/board/gateworks/gw_ventana/800mhz_4x128mx16.cfg
new file mode 100644
index 0000000..1069342
--- /dev/null
+++ b/board/gateworks/gw_ventana/800mhz_4x128mx16.cfg
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright (C) 2013 Boundary Devices
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+DATA 4, MX6_MMDC_P0_MDPDC, 0x0002002D
+DATA 4, MX6_MMDC_P0_MDCFG0, 0x40435323
+DATA 4, MX6_MMDC_P0_MDCFG1, 0xB66E8D63
+DATA 4, MX6_MMDC_P0_MDCFG2, 0x01FF00DB
+DATA 4, MX6_MMDC_P0_MDRWD, 0x000026D2
+DATA 4, MX6_MMDC_P0_MDOR, 0x00431023
+DATA 4, MX6_MMDC_P0_MDOTC, 0x00333030
+DATA 4, MX6_MMDC_P0_MDPDC, 0x0002556D
+DATA 4, MX6_MMDC_P0_MDASP, 0x00000027
+DATA 4, MX6_MMDC_P0_MDCTL, 0x831A0000
+DATA 4, MX6_MMDC_P0_MDSCR, 0x04008032
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00008033
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00048031
+DATA 4, MX6_MMDC_P0_MDSCR, 0x13208030
+DATA 4, MX6_MMDC_P0_MDSCR, 0x04008040
+DATA 4, MX6_MMDC_P0_MPZQHWCTRL, 0xA1390003
+DATA 4, MX6_MMDC_P1_MPZQHWCTRL, 0xA1390003
+DATA 4, MX6_MMDC_P0_MDREF, 0x00005800
+DATA 4, MX6_MMDC_P0_MPODTCTRL, 0x00022227
+DATA 4, MX6_MMDC_P1_MPODTCTRL, 0x00022227
+DATA 4, MX6_MMDC_P0_MPDGCTRL0, 0x420F020F
+DATA 4, MX6_MMDC_P0_MPDGCTRL1, 0x01760175
+DATA 4, MX6_MMDC_P1_MPDGCTRL0, 0x41640171
+DATA 4, MX6_MMDC_P1_MPDGCTRL1, 0x015E0160
+DATA 4, MX6_MMDC_P0_MPRDDLCTL, 0x45464B4A
+DATA 4, MX6_MMDC_P1_MPRDDLCTL, 0x49484A46
+DATA 4, MX6_MMDC_P0_MPWRDLCTL, 0x40402E32
+DATA 4, MX6_MMDC_P1_MPWRDLCTL, 0x3A3A3231
+DATA 4, MX6_MMDC_P0_MPWLDECTRL0, 0x003A003A
+DATA 4, MX6_MMDC_P0_MPWLDECTRL1, 0x0030002F
+DATA 4, MX6_MMDC_P1_MPWLDECTRL0, 0x002F0038
+DATA 4, MX6_MMDC_P1_MPWLDECTRL1, 0x00270039
+DATA 4, MX6_MMDC_P0_MPMUR0, 0x00000800
+DATA 4, MX6_MMDC_P1_MPMUR0, 0x00000800
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00000000
+DATA 4, MX6_MMDC_P0_MAPSR, 0x00011006
diff --git a/board/gateworks/gw_ventana/Makefile b/board/gateworks/gw_ventana/Makefile
new file mode 100644
index 0000000..b8b94b6
--- /dev/null
+++ b/board/gateworks/gw_ventana/Makefile
@@ -0,0 +1,10 @@ 
+#
+# Copyright (C) 2012-2013, Guennadi Liakhovetski <lg@denx.de>
+# (C) Copyright 2012-2013 Freescale Semiconductor, Inc.
+# Copyright (C) 2013, Gateworks Corporation
+#
+# SPDX-License-Identifier:  GPL-2.0+
+#
+
+obj-y  := gw_ventana.o
+
diff --git a/board/gateworks/gw_ventana/README b/board/gateworks/gw_ventana/README
new file mode 100644
index 0000000..9de55ba
--- /dev/null
+++ b/board/gateworks/gw_ventana/README
@@ -0,0 +1,49 @@ 
+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
+------------------------------
+
+The i.MX6 BOOT ROM expects some headers 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.
+
+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
+with:
+
+kobs-ng init -v -x --search_exponent=1 u-boot.imx
+
+This information is taken from
+
+https://trac.gateworks.com/wiki/ventana%3Abuild_uboot
+
+2. Build
+--------
+
+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.
+
+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
+
+To build U-Boot for the MX6Q,1GB,NAND FLASH for example:
+
+ make gwventanaq1g_config
+ make u-boot.imx
+
diff --git a/board/gateworks/gw_ventana/clocks.cfg b/board/gateworks/gw_ventana/clocks.cfg
new file mode 100644
index 0000000..31790e7
--- /dev/null
+++ b/board/gateworks/gw_ventana/clocks.cfg
@@ -0,0 +1,41 @@ 
+/*
+ * Copyright (C) 2013 Gateworks Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Device Configuration Data (DCD)
+ *
+ * Each entry must have the format:
+ * Addr-type           Address        Value
+ *
+ * where:
+ *      Addr-type register length (1,2 or 4 bytes)
+ *      Address   absolute address of the register
+ *      value     value to be stored in the register
+ */
+
+/* set the default clock gate to save power */
+DATA 4, CCM_CCGR0, 0x00C03F3F
+DATA 4, CCM_CCGR1, 0x0030FC03
+DATA 4, CCM_CCGR2, 0x0FFFC000
+DATA 4, CCM_CCGR3, 0x3FF00000
+DATA 4, CCM_CCGR4, 0xFFFFF300 /* enable NAND/GPMI/BCH clocks */
+DATA 4, CCM_CCGR5, 0x0F0000C3
+DATA 4, CCM_CCGR6, 0x000003FF
+
+/* enable AXI cache for VDOA/VPU/IPU */
+DATA 4, MX6_IOMUXC_GPR4, 0xF00000CF
+/* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
+DATA 4, MX6_IOMUXC_GPR6, 0x007F007F
+DATA 4, MX6_IOMUXC_GPR7, 0x007F007F
+
+/*
+ * Setup CCM_CCOSR register as follows:
+ *
+ * cko1_en  = 1    --> CKO1 enabled
+ * cko1_div = 111  --> divide by 8
+ * cko1_sel = 1011 --> ahb_clk_root
+ *
+ * This sets CKO1 at ahb_clk_root/8 = 132/8 = 16.5 MHz
+ */
+DATA 4, CCM_CCOSR, 0x000000fb
diff --git a/board/gateworks/gw_ventana/ddr-setup.cfg b/board/gateworks/gw_ventana/ddr-setup.cfg
new file mode 100644
index 0000000..2748d40
--- /dev/null
+++ b/board/gateworks/gw_ventana/ddr-setup.cfg
@@ -0,0 +1,96 @@ 
+/*
+ * Copyright (C) 2013 Boundary Devices
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Device Configuration Data (DCD)
+ *
+ * Each entry must have the format:
+ * Addr-type           Address        Value
+ *
+ * where:
+ *      Addr-type register length (1,2 or 4 bytes)
+ *      Address   absolute address of the register
+ *      value     value to be stored in the register
+ */
+
+/*
+ * DDR3 settings
+ * MX6Q    ddr is limited to 1066 Mhz	currently 1056 MHz(528 MHz clock),
+ *	   memory bus width: 64 bits	x16/x32/x64
+ * MX6DL   ddr is limited to 800 MHz(400 MHz clock)
+ *	   memory bus width: 64 bits	x16/x32/x64
+ * MX6SOLO ddr is limited to 800 MHz(400 MHz clock)
+ *	   memory bus width: 32 bits	x16/x32
+ */
+DATA 4, MX6_IOM_DRAM_SDQS0, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS1, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS2, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS3, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS4, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS5, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS6, 0x00000030
+DATA 4, MX6_IOM_DRAM_SDQS7, 0x00000030
+
+DATA 4, MX6_IOM_GRP_B0DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B1DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B2DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B3DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B4DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B5DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B6DS, 0x00000030
+DATA 4, MX6_IOM_GRP_B7DS, 0x00000030
+DATA 4, MX6_IOM_GRP_ADDDS, 0x00000030
+/* 40 Ohm drive strength for cs0/1,sdba2,cke0/1,sdwe */
+DATA 4, MX6_IOM_GRP_CTLDS, 0x00000030
+
+DATA 4, MX6_IOM_DRAM_DQM0, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM1, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM2, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM3, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM4, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM5, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM6, 0x00020030
+DATA 4, MX6_IOM_DRAM_DQM7, 0x00020030
+
+DATA 4, MX6_IOM_DRAM_CAS, 0x00020030
+DATA 4, MX6_IOM_DRAM_RAS, 0x00020030
+DATA 4, MX6_IOM_DRAM_SDCLK_0, 0x00020030
+DATA 4, MX6_IOM_DRAM_SDCLK_1, 0x00020030
+
+DATA 4, MX6_IOM_DRAM_RESET, 0x00020030
+DATA 4, MX6_IOM_DRAM_SDCKE0, 0x00003000
+DATA 4, MX6_IOM_DRAM_SDCKE1, 0x00003000
+
+DATA 4, MX6_IOM_DRAM_SDODT0, 0x00003030
+DATA 4, MX6_IOM_DRAM_SDODT1, 0x00003030
+
+/* (differential input) */
+DATA 4, MX6_IOM_DDRMODE_CTL, 0x00020000
+/* (differential input) */
+DATA 4, MX6_IOM_GRP_DDRMODE, 0x00020000
+/* disable ddr pullups */
+DATA 4, MX6_IOM_GRP_DDRPKE, 0x00000000
+DATA 4, MX6_IOM_DRAM_SDBA2, 0x00000000
+/* 40 Ohm drive strength for cs0/1,sdba2,cke0/1,sdwe */
+DATA 4, MX6_IOM_GRP_DDR_TYPE, 0x000C0000
+
+/* Read data DQ Byte0-3 delay */
+DATA 4, MX6_MMDC_P0_MPRDDQBY0DL, 0x33333333
+DATA 4, MX6_MMDC_P0_MPRDDQBY1DL, 0x33333333
+DATA 4, MX6_MMDC_P0_MPRDDQBY2DL, 0x33333333
+DATA 4, MX6_MMDC_P0_MPRDDQBY3DL, 0x33333333
+DATA 4, MX6_MMDC_P1_MPRDDQBY0DL, 0x33333333
+DATA 4, MX6_MMDC_P1_MPRDDQBY1DL, 0x33333333
+DATA 4, MX6_MMDC_P1_MPRDDQBY2DL, 0x33333333
+DATA 4, MX6_MMDC_P1_MPRDDQBY3DL, 0x33333333
+
+/*
+ * MDMISC	mirroring	interleaved (row/bank/col)
+ */
+DATA 4, MX6_MMDC_P0_MDMISC, 0x00081740
+
+/*
+ * MDSCR	con_req
+ */
+DATA 4, MX6_MMDC_P0_MDSCR, 0x00008000
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c
new file mode 100644
index 0000000..418d1f8
--- /dev/null
+++ b/board/gateworks/gw_ventana/gw_ventana.c
@@ -0,0 +1,1729 @@ 
+/*
+ * Copyright (C) 2013 Gateworks Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/mx6-pins.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/mxc_hdmi.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/errno.h>
+#include <asm/gpio.h>
+#include <asm/imx-common/iomux-v3.h>
+#include <asm/imx-common/mxc_i2c.h>
+#include <asm/imx-common/boot_mode.h>
+#include <asm/imx-common/sata.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/fb.h>
+#include <mmc.h>
+#include <fsl_esdhc.h>
+#include <micrel.h>
+#include <miiphy.h>
+#include <netdev.h>
+#include <ipu_pixfmt.h>
+#include <i2c.h>
+#include <fdt_support.h>
+#include <jffs2/load_kernel.h>
+#include <mtd_node.h>
+#include <spi_flash.h>
+#include <hwconfig.h>
+#include <fuse.h>
+
+#include "ventana_eeprom.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define UART_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |		\
+	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED |		\
+	PAD_CTL_DSE_40ohm   | PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
+
+#define USDHC_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE |		\
+	PAD_CTL_PUS_47K_UP  | PAD_CTL_SPEED_LOW |		\
+	PAD_CTL_DSE_80ohm   | PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
+
+#define ENET_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |		\
+	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED	  |		\
+	PAD_CTL_DSE_40ohm   | PAD_CTL_HYS)
+
+#define SPI_PAD_CTRL (PAD_CTL_HYS |				\
+	PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_MED |		\
+	PAD_CTL_DSE_40ohm     | PAD_CTL_SRE_FAST)
+
+#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 DIO_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |		\
+	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED |		\
+	PAD_CTL_DSE_34ohm | PAD_CTL_HYS | PAD_CTL_SRE_FAST)
+
+#define WEAK_PULLUP (PAD_CTL_PUS_100K_UP |			\
+	PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS |	\
+	PAD_CTL_SRE_SLOW)
+
+#define OUTPUT_40OHM (PAD_CTL_SPEED_MED|PAD_CTL_DSE_40ohm)
+
+/* UART1, RS485 */
+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),
+};
+
+/* UART2, 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),
+};
+
+#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
+
+/* I2C1, GSC */
+struct i2c_pads_info i2c_pad_info0 = {
+	.scl = {
+		.i2c_mode = MX6_PAD_EIM_D21__I2C1_SCL | PC,
+		.gpio_mode = MX6_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,
+		.gp = IMX_GPIO_NR(3, 28)
+	}
+};
+
+/* I2C2, PFUSE, PCIe Switch/Clock/Mezz */
+struct i2c_pads_info i2c_pad_info1 = {
+	.scl = {
+		.i2c_mode = MX6_PAD_KEY_COL3__I2C2_SCL | PC,
+		.gpio_mode = MX6_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,
+		.gp = IMX_GPIO_NR(4, 13)
+	}
+};
+
+/* I2C3, Accel, Audio Codec, Video Decoder, Video Encoder, MIPI, LVDS, DIO */
+struct i2c_pads_info i2c_pad_info2 = {
+	.scl = {
+		.i2c_mode = MX6_PAD_GPIO_3__I2C3_SCL | PC,
+		.gpio_mode = MX6_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,
+		.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 */
+};
+
+/* 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),
+	/* PHY nRST */
+	MX6_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),
+};
+
+#ifdef CONFIG_CMD_NAND
+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));
+
+	/* config gpmi and bch clock to 100 MHz */
+	clrsetbits_le32(&mxc_ccm->cs2cdr,
+			MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK |
+			MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK |
+			MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK,
+			MXC_CCM_CS2CDR_ENFC_CLK_PODF(0) |
+			MXC_CCM_CS2CDR_ENFC_CLK_PRED(3) |
+			MXC_CCM_CS2CDR_ENFC_CLK_SEL(3));
+
+	/* enable gpmi and bch clock gating */
+	setbits_le32(&mxc_ccm->CCGR4,
+		     MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK |
+		     MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK |
+		     MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK |
+		     MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK |
+		     MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_OFFSET);
+
+	/* enable apbh clock gating */
+	setbits_le32(&mxc_ccm->CCGR0, MXC_CCM_CCGR0_APBHDMA_MASK);
+}
+#endif
+
+static void setup_iomux_enet(void)
+{
+	imx_iomux_v3_setup_multiple_pads(enet_pads, ARRAY_SIZE(enet_pads));
+
+	/* toggle PHY_RST# */
+	gpio_direction_output(IMX_GPIO_NR(1, 30), 0);
+	mdelay(2);
+	gpio_set_value(IMX_GPIO_NR(1, 30), 1);
+}
+
+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));
+}
+
+#ifdef CONFIG_USB_EHCI_MX6
+iomux_v3_cfg_t const usb_pads[] = {
+	MX6_PAD_GPIO_1__USB_OTG_ID   | MUX_PAD_CTRL(WEAK_PULLUP),
+	MX6_PAD_KEY_COL4__USB_OTG_OC | MUX_PAD_CTRL(WEAK_PULLUP),
+	MX6_PAD_EIM_D22__GPIO3_IO22  | MUX_PAD_CTRL(OUTPUT_40OHM),
+};
+
+int board_ehci_hcd_init(int port)
+{
+	/* Reset USB hub */
+	imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT0__GPIO1_IO16 |
+			MUX_PAD_CTRL(NO_PAD_CTRL));
+	gpio_direction_output(IMX_GPIO_NR(1, 16), 0);
+	mdelay(2);
+	gpio_set_value(IMX_GPIO_NR(1, 16), 1);
+
+	return 0;
+}
+
+int board_ehci_power(int port, int on)
+{
+	if (port)
+		return 0;
+	gpio_set_value(IMX_GPIO_NR(3, 22), on);
+	return 0;
+}
+#endif /* CONFIG_USB_EHCI_MX6 */
+
+#ifdef CONFIG_FSL_ESDHC
+struct fsl_esdhc_cfg usdhc_cfg[1] = {
+	{USDHC3_BASE_ADDR},
+};
+
+int board_mmc_getcd(struct mmc *mmc)
+{
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	int ret = 0;
+
+	if (cfg->esdhc_base == USDHC3_BASE_ADDR) {
+		/* Card Detect */
+		gpio_direction_input(IMX_GPIO_NR(7, 0));
+		ret = !gpio_get_value(IMX_GPIO_NR(7, 0));
+	}
+
+	return ret;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	s32 status = 0;
+	u32 index = 0;
+
+	usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
+	usdhc_cfg[0].max_bus_width = 4;
+
+	for (index = 0; index < CONFIG_SYS_FSL_USDHC_NUM; ++index) {
+		switch (index) {
+		case 0:
+			imx_iomux_v3_setup_multiple_pads(
+				usdhc3_pads, ARRAY_SIZE(usdhc3_pads));
+			break;
+		default:
+			printf("Warning: you configured more USDHC controllers (%d) then supported by the board (%d)\n",
+			       index + 1, CONFIG_SYS_FSL_USDHC_NUM);
+			return status;
+		}
+
+		status |= fsl_esdhc_initialize(bis, &usdhc_cfg[index]);
+	}
+
+	return status;
+}
+#endif /* CONFIG_FSL_ESDHC */
+
+/* Gateworks System Controller I2C access may NAK when busy - use
+ * retries.
+ */
+int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int retry = 3;
+	int n = 0;
+	int ret;
+
+	while (n++ < retry) {
+		ret = i2c_read(chip, addr, alen, buf, len);
+		if (!ret)
+			break;
+		printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
+		       n, ret);
+		if (ret != -ENODEV)
+			break;
+		mdelay(10);
+	}
+	return ret;
+}
+
+int gsc_i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int retry = 3;
+	int n = 0;
+	int ret;
+
+	while (n++ < retry) {
+		ret = i2c_write(chip, addr, alen, buf, len);
+		if (!ret)
+			break;
+		printf("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
+		       n, ret);
+		if (ret != -ENODEV)
+			break;
+		mdelay(10);
+	}
+	mdelay(1);
+	return ret;
+}
+
+/*
+ * For SPL boot some boards need i2c before SDRAM is initialized so force
+ * variables to live in SRAM
+ */
+static struct ventana_board_info __attribute__((section(".data"))) ventana_info;
+
+/* read ventana EEPROM and return structure or NULL on error
+ * should be called once, the first time eeprom data is needed
+ */
+static void
+read_eeprom(void)
+{
+	int i;
+	int chksum;
+	struct ventana_board_info *info = &ventana_info;
+	unsigned char *buf = (unsigned char *)&ventana_info;
+	int n = 0;
+
+	memset(info, 0, sizeof(ventana_info));
+
+	/*  wait for bus and device exist - we will not boot w/o our EEPROM */
+	while (1) {
+		if (0 == i2c_set_bus_num(0) && 0 == i2c_probe(0x51))
+			break;
+		mdelay(1);
+		n++;
+	}
+
+	/* read eeprom config section */
+	if (gsc_i2c_read(0x51, 0x00, 1, buf, sizeof(ventana_info))) {
+		printf("EEPROM: Failed to read EEPROM\n");
+		info->model[0] = 0;
+		return;
+	}
+
+	/* sanity checks */
+	if (info->model[0] != 'G' || info->model[1] != 'W') {
+		printf("EEPROM: Invalid Model in EEPROM\n");
+		info->model[0] = 0;
+		return;
+	}
+
+	/* 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))) {
+		printf("EEPROM: Failed EEPROM checksum\n");
+		info->model[0] = 0;
+		return;
+	}
+}
+
+#ifdef CONFIG_CMD_GSC
+int read_hwmon(const char *name, uint reg, uint size, uint low, uint high)
+{
+	unsigned char buf[3];
+	uint ui;
+	int ret;
+
+	printf("%-8s:", name);
+	memset(buf, 0, sizeof(buf));
+	if (gsc_i2c_read(0x29, reg, 1, buf, size)) {
+		printf("fRD\n");
+		ret = -1;
+	} else {
+		ret = 0;
+		ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
+		if (ui == 0xffffff) {
+			printf("fVL");
+		} else if (ui < low) {
+			printf("%d fLO", ui);
+			ret = -2;
+		} else if (ui > high) {
+			printf("%d fHI", ui);
+			ret = -3;
+		} else {
+			printf("%d", ui);
+		}
+	}
+	printf("\n");
+
+	return ret;
+}
+
+int do_gsc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct ventana_board_info *info = &ventana_info;
+
+	i2c_set_bus_num(0);
+	if ((strncasecmp((const char *)info->model, "GW51", 4) == 0)) {
+		read_hwmon("Temp",     0x00, 2, 0, 9000);
+		read_hwmon("VIN",      0x02, 3, 8000, 60000);
+		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
+		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
+		read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
+		read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
+		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
+		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
+		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
+		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
+		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
+	} else if ((strncasecmp((const char *)info->model, "GW52", 4) == 0)) {
+		read_hwmon("Temp",     0x00, 2, 0, 9000);
+		read_hwmon("VIN",      0x02, 3, 8000, 60000);
+		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
+		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
+		read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
+		read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
+		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
+		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
+		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
+		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
+		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
+		read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
+	} else if ((strncasecmp((const char *)info->model, "GW53", 4) == 0)) {
+		read_hwmon("Temp",     0x00, 2, 0, 9000);
+		read_hwmon("VIN",      0x02, 3, 8000, 60000);
+		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
+		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
+		read_hwmon("VDD_CORE", 0x0e, 3, 1175*0.9, 1175*1.1);
+		read_hwmon("VDD_SOC",  0x11, 3, 1175*0.9, 1175*1.1);
+		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
+		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
+		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
+		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
+		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
+		read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
+	} else if ((strncasecmp((const char *)info->model, "GW54", 4) == 0)) {
+		read_hwmon("Temp",     0x00, 2, 0, 9000);
+		read_hwmon("VIN",      0x02, 3, 8000, 60000);
+		read_hwmon("VDD_3P3",  0x05, 3, 3300*0.9, 3300*1.1);
+		read_hwmon("VBATT",    0x08, 3, 2000*0.9, 3000*1.1);
+		read_hwmon("VDD_CORE", 0x0e, 3, 1375*0.9, 1375*1.1);
+		read_hwmon("VDD_SOC",  0x11, 3, 1375*0.9, 1375*1.1);
+		read_hwmon("VDD_HIGH", 0x14, 3, 3000*0.9, 3000*1.1);
+		read_hwmon("VDD_DDR",  0x17, 3, 1500*0.9, 1500*1.1);
+		read_hwmon("VDD_5P0",  0x0b, 3, 5000*0.9, 5000*1.1);
+		read_hwmon("VDD_2P5",  0x23, 3, 2500*0.9, 2500*1.1);
+		read_hwmon("VDD_1P8",  0x1d, 3, 1800*0.9, 1800*1.1);
+		read_hwmon("VDD_1P0",  0x20, 3, 1000*0.9, 1000*1.1);
+	}
+	return 0;
+}
+
+U_BOOT_CMD(gsc, 1, 1, do_gsc,
+	   "GSC test",
+	   ""
+);
+#endif /* CONFIG_CMD_GSC */
+
+
+/* get_mac from env string, with default
+ */
+static void get_mac(char *envvar, unsigned char *def)
+{
+	char str[20];
+	char *env = getenv(envvar);
+
+	if (!env) {
+		sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
+			def[0], def[1], def[2], def[3], def[4], def[5]);
+		setenv(envvar, str);
+	}
+}
+
+#ifdef CONFIG_SERIAL_TAG
+/* called when setting up ATAGS before booting kernel
+ * populate serialnum from the following (in order of priority):
+ *   serial# env var
+ *   eeprom
+ */
+void get_board_serial(struct tag_serialnr *serialnr)
+{
+	char *serial = getenv("serial#");
+
+	if (serial) {
+		serialnr->high = 0;
+		serialnr->low = simple_strtoul(serial, NULL, 10);
+	} else if (ventana_info.model[0]) {
+		serialnr->high = 0;
+		serialnr->low = ventana_info.serial;
+	} else {
+		serialnr->high = 0;
+		serialnr->low = 0;
+	}
+}
+#endif
+
+#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),
+};
+
+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));
+}
+#endif
+
+int board_phy_config(struct phy_device *phydev)
+{
+	unsigned short val;
+
+	/* Marvel 88E1510 */
+	if (phydev->phy_id == 0x1410dd1) {
+		/* Errata 3.1 - PHY initialization */
+		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff);
+		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214b);
+		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
+		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0c28);
+		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
+		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xb233);
+		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214d);
+		phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xcc0c);
+		phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
+		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00fb);
+		phy_write(phydev, MDIO_DEVAD_NONE,  7, 0xc00d);
+		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
+
+		/* LED configuration (See datasheet section 2.26.4)
+		 * LED[0] (SPD:Amber) R16_3.3:0 to 0111: on-GbE link
+		 * LED[1] (LNK:Green) R16_3.7:4 to 0001: on-link, blink-activity
+		 */
+		phy_write(phydev, MDIO_DEVAD_NONE, 22, 3);
+		val = phy_read(phydev, MDIO_DEVAD_NONE, 16);
+		val &= 0xff00;
+		val |= 0x0017;
+		phy_write(phydev, MDIO_DEVAD_NONE, 16, val);
+		phy_write(phydev, MDIO_DEVAD_NONE, 22, 0);
+	}
+
+	if (phydev->drv->config)
+		phydev->drv->config(phydev);
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bis)
+{
+	int ret;
+
+	setup_iomux_enet();
+
+#ifdef CONFIG_FEC_MXC
+	ret = cpu_eth_init(bis);
+	if (ret)
+		printf("FEC MXC: %s:failed\n", __func__);
+#endif
+
+#ifdef CONFIG_MV_UDC
+	/* For otg ethernet*/
+	usb_eth_initialize(bis);
+#endif
+
+	return 0;
+}
+
+static void setup_board_gpio(const char *model)
+{
+	const char *s;
+	char arg[10];
+	size_t len;
+	int i;
+	enum {
+		GW51xx,
+		GW52xx,
+		GW53xx,
+		GW54xx,
+		UNKNOWN,
+	};
+	struct dio_cfg {
+		iomux_v3_cfg_t gpio_padmux;
+		unsigned gpio_param;
+		iomux_v3_cfg_t pwm_padmux;
+		unsigned pwm_param;
+	};
+	int board_type = UNKNOWN;
+	struct dio_cfg dio_cfg[] = {
+		/* GW51xx */
+		{ 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 },
+
+		/* GW52xx */
+		{ 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 },
+
+		/* GW53xx */
+		{ 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 },
+
+		/* GW54xx */
+		{ 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 },
+	};
+
+	if (strncasecmp(model, "GW51", 4) == 0) {
+		board_type = GW51xx;
+
+		/* PANLEDG# (GRN off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
+
+		/* PANLEDR# (RED off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
+
+		/* GPS_SHDN */
+		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_2__GPIO1_IO02 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 2), 1);
+
+		/* Analog video codec power enable */
+		imx_iomux_v3_setup_pad(MX6_PAD_CSI0_DATA_EN__GPIO5_IO20 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(5, 20), 1);
+
+		/* Expansion IO0 - PWREN# */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
+
+		/* Expansion IO1 - IRQ# */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_input(IMX_GPIO_NR(2, 18));
+	} /* end GW51xx */
+
+	else if (strncasecmp(model, "GW52", 4) == 0) {
+		board_type = GW52xx;
+
+		/* PANLEDG# (GRN off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
+
+		/* PANLEDR# (RED off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
+
+		/* MX6_LOCLED# (off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
+
+		/* GPS_SHDN */
+		imx_iomux_v3_setup_pad(MX6_PAD_ENET_RXD0__GPIO1_IO27 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 27), 1);
+
+		/* Expansion IO0 - PWREN# */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
+
+		/* Expansion IO1 - IRQ# */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_input(IMX_GPIO_NR(2, 18));
+
+		/* MSATA Enable */
+		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		if (is_cpu_type(MXC_CPU_MX6Q)) {
+			gpio_direction_output(IMX_GPIO_NR(2, 8),
+					      (hwconfig("msata")) ? 1 : 0);
+			printf("MSATA: %s\n", (hwconfig("msata") ?
+			       "enabled" : "disabled"));
+		} else {
+			gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
+		}
+
+		/* USBOTG Select (PCISKT or FrontPanel) */
+		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_2__GPIO1_IO02 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 2), 0);
+
+		/* Analog video codec power enable */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
+
+		/* UART2_EN# */
+		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		printf("RS232: %s\n", (hwconfig("rs232")) ?
+		       "enabled" : "disabled");
+		gpio_direction_output(IMX_GPIO_NR(2, 11),
+				      (hwconfig("rs232")) ? 0 : 1);
+		/* TODO: flush UART RX FIFO after disable */
+	} /* end GW52xx */
+
+	else if (strncasecmp(model, "GW53", 4) == 0) {
+		board_type = GW53xx;
+
+		/* PANLEDG# (GRN off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
+
+		/* PANLEDR# (RED off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
+
+		/* MX6_LOCLED# (off) */
+		imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
+
+		/* GPS_SHDN */
+		imx_iomux_v3_setup_pad(MX6_PAD_ENET_RXD0__GPIO1_IO27 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 27), 1);
+
+		/* Expansion IO0 - PWREN# */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
+
+		/* Expansion IO1 - IRQ# */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_input(IMX_GPIO_NR(2, 18));
+
+		/* MSATA Enable */
+		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		if (is_cpu_type(MXC_CPU_MX6Q)) {
+			gpio_direction_output(IMX_GPIO_NR(2, 8),
+					      (hwconfig("msata")) ? 1 : 0);
+			printf("MSATA: %s\n", (hwconfig("msata") ?
+			       "enabled" : "disabled"));
+		} else {
+			gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
+		}
+
+		/* Analog video codec power enable */
+		imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
+
+		/* UART2_EN# */
+		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		printf("RS232: %s\n", (hwconfig("rs232")) ?
+		       "enabled" : "disabled");
+		gpio_direction_output(IMX_GPIO_NR(2, 11),
+				      (hwconfig("rs232")) ? 0 : 1);
+		/* TODO: flush UART RX FIFO after disable */
+	} /* end GW53xx */
+
+	else if (strncasecmp(model, "GW54", 4) == 0) {
+		board_type = GW54xx;
+		if (strncasecmp(model, "GW5400-A", 8) == 0) {
+			/* PANLEDG# (GRN off) */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
+
+			/* PANLEDR# (RED off) */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL2__GPIO4_IO10 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 10), 1);
+
+			/* MX6_LOCLED# (off) */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
+
+			/* MIPI DIO */
+			imx_iomux_v3_setup_pad(MX6_PAD_SD1_DAT3__GPIO1_IO21 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+
+			/* RS485 Transmit Enable */
+			imx_iomux_v3_setup_pad(MX6_PAD_EIM_D24__GPIO3_IO24 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(3, 24), 0);
+
+			/* Expansion IO0 - PWREN# */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 7), 0);
+
+			/* Expansion IO1 - IRQ# */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW1__GPIO4_IO09 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_input(IMX_GPIO_NR(4, 9));
+		}
+
+		else if ((strncasecmp(model, "GW5400", 6) == 0) ||
+			 (strncasecmp(model, "GW5410", 6) == 0)
+		) {
+			/* PANLEDG# (GRN off) */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_COL0__GPIO4_IO06 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 6), 1);
+
+			/* PANLEDR# (RED off) */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW0__GPIO4_IO07 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 7), 1);
+
+			/* MX6_LOCLED# (off) */
+			imx_iomux_v3_setup_pad(MX6_PAD_KEY_ROW4__GPIO4_IO15 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(4, 15), 1);
+
+			/* RS485 Transmit Enable */
+			imx_iomux_v3_setup_pad(MX6_PAD_SD3_DAT4__GPIO7_IO01 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(7, 1), 0);
+
+			/* Expansion IO0 - PWREN# */
+			imx_iomux_v3_setup_pad(MX6_PAD_EIM_A19__GPIO2_IO19 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(2, 19), 0);
+
+			/* Expansion IO1 - IRQ# */
+			imx_iomux_v3_setup_pad(MX6_PAD_EIM_A20__GPIO2_IO18 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_input(IMX_GPIO_NR(2, 18));
+
+			/* MSATA Enable */
+			imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT0__GPIO2_IO08 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			if (is_cpu_type(MXC_CPU_MX6Q)) {
+				gpio_direction_output(IMX_GPIO_NR(2, 8),
+						      (hwconfig("msata")) ?
+						      1 : 0);
+				printf("MSATA: %s\n", (hwconfig("msata") ?
+				       "enabled" : "disabled"));
+			} else {
+				gpio_direction_output(IMX_GPIO_NR(2, 8), 0);
+			}
+
+			/* Analog video codec power enable */
+			imx_iomux_v3_setup_pad(MX6_PAD_EIM_D31__GPIO3_IO31 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+			gpio_direction_output(IMX_GPIO_NR(3, 31), 1);
+		}
+
+		/* UART2_EN# */
+		imx_iomux_v3_setup_pad(MX6_PAD_SD4_DAT3__GPIO2_IO11 |
+					       MUX_PAD_CTRL(NO_PAD_CTRL));
+		printf("RS232: %s\n", (hwconfig("rs232")) ?
+		       "enabled" : "disabled");
+		gpio_direction_output(IMX_GPIO_NR(2, 11),
+				      (hwconfig("rs232")) ? 0 : 1);
+		/* TODO: flush UART RX FIFO after disable */
+
+		/* DIOI2C_DIS# */
+		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_19__GPIO4_IO05 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(4,  5), 0);
+	} /* end GW54xx */
+
+	/* Configure DIO pinmux/padctl registers
+	 * see IMX6DQRM/IMX6SDLRM IOMUXC_SW_PAD_CTL_PAD_* register definitions
+	 */
+	if (board_type > UNKNOWN)
+		return;
+	for (i = 0; i < 4; i++) {
+		struct dio_cfg *cfg = &dio_cfg[(4*board_type)+i];
+		unsigned ctrl = DIO_PAD_CTRL;
+
+		sprintf(arg, "dio%d", i);
+		if (hwconfig(arg)) {
+			s = hwconfig_subarg(arg, "padctrl", &len);
+			if (s)
+				ctrl = simple_strtoul(s, NULL, 16) & 0x3ffff;
+			if (hwconfig_subarg_cmp(arg, "mode", "gpio")) {
+				printf("DIO%d:  GPIO%d_IO%02d (gpio-%d)\n", i,
+				       (cfg->gpio_param/32)+1,
+				       cfg->gpio_param%32,
+				       cfg->gpio_param);
+				imx_iomux_v3_setup_pad(cfg->gpio_padmux |
+						       MUX_PAD_CTRL(ctrl));
+				gpio_direction_input(cfg->gpio_param);
+			} else if (hwconfig_subarg_cmp("dio2", "mode", "pwm") &&
+				   cfg->pwm_padmux) {
+				printf("DIO%d:  pwm%d\n", i, cfg->pwm_param);
+				imx_iomux_v3_setup_pad(cfg->pwm_padmux |
+						       MUX_PAD_CTRL(ctrl));
+			}
+		}
+	}
+}
+
+static int setup_pcie(void)
+{
+	struct ventana_board_info *info = &ventana_info;
+
+	if ((strncasecmp((const char *)info->model, "GW51", 4) == 0)) {
+		/* assert PCI_RST#
+		 * (will be released by OS when clock is valid) */
+		imx_iomux_v3_setup_pad(MX6_PAD_GPIO_0__GPIO1_IO00 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 0), 0);
+	} else if ((strncasecmp((const char *)info->model, "GW52", 4) == 0)) {
+		/* assert PCI_RST#
+		 * (will be released by OS when clock is valid) */
+		imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
+	} else if ((strncasecmp((const char *)info->model, "GW53", 4) == 0)) {
+		/* assert PCI_RST#
+		 * (will be released by OS when clock is valid) */
+		imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
+	} else if ((strncasecmp((const char *)info->model, "GW54", 4) == 0)) {
+		/* PCICK_SSON: disable spread-spectrum clock */
+		imx_iomux_v3_setup_pad(MX6_PAD_SD1_CLK__GPIO1_IO20 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 20), 0);
+
+		/* assert PCI_RST#
+		 * (will be released by OS when clock is valid) */
+		imx_iomux_v3_setup_pad(MX6_PAD_ENET_TXD1__GPIO1_IO29 |
+				       MUX_PAD_CTRL(NO_PAD_CTRL));
+		gpio_direction_output(IMX_GPIO_NR(1, 29), 0);
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_VIDEO_IPUV3)
+
+static iomux_v3_cfg_t const backlight_pads[] = {
+	/* Backlight on MIPI connector: J16 */
+	MX6_PAD_SD2_CMD__GPIO1_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
+
+	/* Backlight CABEN on LVDS connector: J6 */
+	MX6_PAD_SD2_CLK__GPIO1_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
+};
+
+struct display_info_t {
+	int	bus;
+	int	addr;
+	int	pixfmt;
+	int	(*detect)(struct display_info_t const *dev);
+	void	(*enable)(struct display_info_t const *dev);
+	struct	fb_videomode mode;
+};
+
+
+static int detect_hdmi(struct display_info_t const *dev)
+{
+	struct hdmi_regs *hdmi  = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR;
+	return readb(&hdmi->phy_stat0) & HDMI_PHY_HPD;
+}
+
+static void do_enable_hdmi(struct display_info_t const *dev)
+{
+	imx_enable_hdmi_phy();
+}
+
+static int detect_i2c(struct display_info_t const *dev)
+{
+	return ((0 == i2c_set_bus_num(dev->bus)) &&
+		(0 == i2c_probe(dev->addr)));
+}
+
+static void enable_lvds(struct display_info_t const *dev)
+{
+	struct iomuxc *iomux = (struct iomuxc *)
+				IOMUXC_BASE_ADDR;
+
+	/* set CH0 data width to 24bit (IOMUXC_GPR2:5 0=18bit, 1=24bit) */
+	u32 reg = readl(&iomux->gpr[2]);
+	reg |= IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT;
+	writel(reg, &iomux->gpr[2]);
+
+	/* Disable CABC:
+	 * when enabled this feature sets backlight automatically according
+	 * to content which may cause annoying unstable backlight issue
+	 */
+	gpio_direction_output(IMX_GPIO_NR(1, 10), 0);
+
+	/* Enable Backlight */
+	imx_iomux_v3_setup_pad(MX6_PAD_SD1_CMD__GPIO1_IO18 |
+			       MUX_PAD_CTRL(NO_PAD_CTRL));
+	gpio_direction_output(IMX_GPIO_NR(1, 18), 1);
+}
+
+static struct display_info_t const displays[] = {{
+	/* HDMI Output */
+	.bus	= -1,
+	.addr	= 0,
+	.pixfmt	= IPU_PIX_FMT_RGB24,
+	.detect	= detect_hdmi,
+	.enable	= do_enable_hdmi,
+	.mode	= {
+		.name           = "HDMI",
+		.refresh        = 60,
+		.xres           = 1024,
+		.yres           = 768,
+		.pixclock       = 15385,
+		.left_margin    = 220,
+		.right_margin   = 40,
+		.upper_margin   = 21,
+		.lower_margin   = 7,
+		.hsync_len      = 60,
+		.vsync_len      = 10,
+		.sync           = FB_SYNC_EXT,
+		.vmode          = FB_VMODE_NONINTERLACED
+} }, {
+	/* HannStar HSD100PXN1-A00 with egalx_ts controller
+	 * (aka Freescale MXC-LVDS1 10" 1024x768 60Hz LCD touchscreen)
+	 */
+	.bus	= 2,
+	.addr	= 0x4,
+	.pixfmt	= IPU_PIX_FMT_LVDS666,
+	.detect	= detect_i2c,
+	.enable	= enable_lvds,
+	.mode	= {
+		.name           = "Hannstar-XGA",
+		.refresh        = 60,
+		.xres           = 1024,
+		.yres           = 768,
+		.pixclock       = 15385,
+		.left_margin    = 220,
+		.right_margin   = 40,
+		.upper_margin   = 21,
+		.lower_margin   = 7,
+		.hsync_len      = 60,
+		.vsync_len      = 10,
+		.sync           = FB_SYNC_EXT,
+		.vmode          = FB_VMODE_NONINTERLACED
+} } };
+
+int board_video_skip(void)
+{
+	int i;
+	int ret;
+	char const *panel = getenv("panel");
+	if (!panel) {
+		for (i = 0; i < ARRAY_SIZE(displays); i++) {
+			struct display_info_t const *dev = displays+i;
+			if (dev->detect(dev)) {
+				panel = dev->mode.name;
+				printf("auto-detected panel %s\n", panel);
+				break;
+			}
+		}
+		if (!panel) {
+			panel = displays[0].mode.name;
+			i = 0;
+			printf("No panel detected: default to %s\n", panel);
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(displays); i++) {
+			if (!strcmp(panel, displays[i].mode.name))
+				break;
+		}
+	}
+	if (i < ARRAY_SIZE(displays)) {
+		ret = ipuv3_fb_init(&displays[i].mode, 0,
+				    displays[i].pixfmt);
+		if (!ret) {
+			displays[i].enable(displays+i);
+			printf("DISP:  %s (%ux%u)\n",
+			       displays[i].mode.name,
+			       displays[i].mode.xres,
+			       displays[i].mode.yres);
+		} else
+			printf("LCD %s cannot be configured: %d\n",
+			       displays[i].mode.name, ret);
+	} else {
+		printf("unsupported panel %s\n", panel);
+		ret = -EINVAL;
+	}
+	return (0 != ret);
+}
+
+static void setup_display(void)
+{
+	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+	struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
+	int reg;
+
+	enable_ipu_clock();
+	imx_setup_hdmi();
+
+	/* Turn on LDB0,IPU,IPU DI0 clocks */
+	reg = readl(&mxc_ccm->CCGR3);
+	reg |= MXC_CCM_CCGR3_LDB_DI0_MASK;
+	writel(reg, &mxc_ccm->CCGR3);
+
+	/* set LDB0, LDB1 clk select to 011/011 */
+	reg = readl(&mxc_ccm->cs2cdr);
+	reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
+		 |MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
+	reg |= (3<<MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
+	      |(3<<MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
+	writel(reg, &mxc_ccm->cs2cdr);
+
+	reg = readl(&mxc_ccm->cscmr2);
+	reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
+	writel(reg, &mxc_ccm->cscmr2);
+
+	reg = readl(&mxc_ccm->chsccdr);
+	reg |= (CHSCCDR_CLK_SEL_LDB_DI0
+		<<MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
+	writel(reg, &mxc_ccm->chsccdr);
+
+	reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
+	     |IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
+	     |IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
+	     |IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
+	     |IOMUXC_GPR2_DATA_WIDTH_CH1_18BIT
+	     |IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
+	     |IOMUXC_GPR2_DATA_WIDTH_CH0_18BIT
+	     |IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
+	     |IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
+	writel(reg, &iomux->gpr[2]);
+
+	reg = readl(&iomux->gpr[3]);
+	reg = (reg & ~IOMUXC_GPR3_LVDS0_MUX_CTL_MASK)
+	    | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
+	       <<IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
+	writel(reg, &iomux->gpr[3]);
+
+	/* backlights off until needed */
+	imx_iomux_v3_setup_multiple_pads(backlight_pads,
+					 ARRAY_SIZE(backlight_pads));
+	gpio_direction_input(IMX_GPIO_NR(1, 10)); /* LVDS */
+	gpio_direction_input(IMX_GPIO_NR(1, 11)); /* MIPI */
+}
+#endif /* CONFIG_VIDEO_IPUV3 */
+
+static int setup_pmic_voltages(void)
+{
+	int ret;
+	unsigned char value, rev_id = 0;
+
+	ret = i2c_set_bus_num(1);
+	if (ret)
+		return ret;
+	if (!i2c_probe(0x8)) {
+		if (i2c_read(0x8, 0, 1, &value, 1)) {
+			printf("Read device ID error!\n");
+			return -1;
+		}
+		if (i2c_read(0x8, 3, 1, &rev_id, 1)) {
+			printf("Read Rev ID error!\n");
+			return -1;
+		}
+		printf("PMIC:  deviceid=%x, revid=%x\n", value, rev_id);
+		/*set VGEN1 to 1.5V and enable*/
+		if (i2c_read(0x8, 0x6c, 1, &value, 1)) {
+			printf("Read VGEN1 error!\n");
+			return -1;
+		}
+		value &= ~0x1f;
+		value |= 0x1e;
+		if (i2c_write(0x8, 0x6c, 1, &value, 1)) {
+			printf("Set VGEN1 error!\n");
+			return -1;
+		}
+		/*set SWBST to 5.0V and enable */
+		if (i2c_read(0x8, 0x66, 1, &value, 1)) {
+			printf("Read SWBST error!\n");
+			return -1;
+		}
+		value &= ~0xf;
+		value |= 0x8;
+		if (i2c_write(0x8, 0x66, 1, &value, 1)) {
+			printf("Set SWBST error!\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_CMD_BMODE
+/* BOOT_CFG1, BOOT_CFG2, BOOT_CFG3, BOOT_CFG4
+ * see Table 8-11 and Table 5-9
+ *  BOOT_CFG1[7] = 1 (boot from NAND)
+ *  BOOT_CFG1[5] = 0 - raw NAND
+ *  BOOT_CFG1[4] = 0 - default pad settings
+ *  BOOT_CFG1[3:2] = 00 - devices = 1
+ *  BOOT_CFG1[1:0] = 00 - Row Address Cycles = 3
+ *  BOOT_CFG2[4:3] = 00 - Boot Search Count = 2
+ *  BOOT_CFG2[2:1] = 01 - Pages In Block = 64
+ *  BOOT_CFG2[0] = 0 - Reset time 12ms
+ */
+static const struct boot_mode board_boot_modes[] = {
+	/* NAND: raw, 64pages per block, 3 row addr cycles,
+	 * 2 copies of FCB/DBBT */
+	{ "nand", MAKE_CFGVAL(0x80, 0x02, 0x00, 0x00) },
+	{ NULL,	0 },
+};
+#endif
+
+/*
+ * Board Support
+ */
+
+/*
+ * Do not overwrite the console
+ * Use always serial for U-Boot console
+ */
+int overwrite_console(void)
+{
+	return 1;
+}
+
+
+/*
+ * very early in the call chain - setup SoC peripherals
+ * (NB: Can not printf from here)
+ */
+int board_early_init_f(void)
+{
+	setup_iomux_uart();
+#ifdef CONFIG_MXC_SPI
+	setup_spi();
+#endif
+	gpio_direction_output(IMX_GPIO_NR(3, 22), 0); /* OTG power off */
+
+	/* Note this gets called again later,
+	 * but needed in case i2c bus is stuck */
+	timer_init();
+	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 defined(CONFIG_VIDEO_IPUV3)
+	setup_display();
+#endif
+
+	return 0;
+}
+
+#if defined(CONFIG_DISPLAY_BOARDINFO)
+/* Identify board and display banner/info
+ */
+#define SRC_SBMR1 0x020d8004  /* holds BOOT_CFG1-BOOT_CFG4 from eFuse/pins */
+#define SRC_SBMR2 0x020d801c
+#define SRC_GPR9  0x020d8040  /* holds copy of BOOT_CFG1-BOOT_CFG4 acted on */
+#define SRC_GPR10 0x020d8044
+
+/* this reads boot_cfg efuse/pins - does not reflect what actually booted
+ */
+void show_boot_mode(uint boot_cfg)
+{
+	switch ((boot_cfg & 0x000000ff) >> 4) {
+	case 0x2:
+		printf("SATA");
+		break;
+	case 0x3:
+		printf("SPI NOR");
+		break;
+	case 0x4:
+	case 0x5:
+		/* BOOT_CFG2[3:4] is devno */
+		printf(" SD%d", (boot_cfg & 0x00001800) >> 11);
+		break;
+	case 0x6:
+	case 0x7:
+		/* BOOT_CFG2[3:4] is devno */
+		printf(" MMC%d", (boot_cfg & 0x00001800) >> 11);
+		break;
+	case 0x8 ... 0xf:
+		printf("NAND");
+		break;
+	default:
+		printf("Unknown");
+		break;
+	}
+	printf(" 0x%08x\n", boot_cfg);
+}
+
+
+int checkboard(void)
+{
+	struct ventana_board_info *info = &ventana_info;
+	uint src_sbmr2 = readl(SRC_SBMR2);
+	uint src_gpr10 = readl(SRC_GPR10);
+
+	/* check for valid i2c busses - if one was 'stuck' it did not get
+	 * initialized
+	 */
+	if (i2c_set_bus_num(0))
+		printf("invalid /dev/i2c-0\n");
+	if (i2c_set_bus_num(1))
+		printf("invalid /dev/i2c-1\n");
+	if (i2c_set_bus_num(2))
+		printf("invalid /dev/i2c-2\n");
+	read_eeprom();
+	if (!(src_sbmr2 & 1<<4)) {
+		/* can consider this 'manufacturing mode' if needed */
+		printf("First boot - eFUSE not blown\n");
+	}
+
+	printf("APP_IMAGE: %s\n", (src_gpr10 & 1<<30) ?
+	       "Secondary" : "Primary");
+	if (src_gpr10 & 1<<29)
+		printf("NAND: bad blocks in application image\n");
+
+#if defined(CONFIG_ENV_IS_IN_SPI_FLASH)
+	printf("Env: SPI FLASH\n");
+#elif defined(CONFIG_ENV_IS_IN_MMC)
+	printf("Env: MMC\n");
+#elif defined(CONFIG_ENV_IS_IN_NAND)
+	printf("Env: NAND FLASH\n");
+#endif
+
+	/* SRC_SBMR1 reflects eFUSE/pin */
+	printf("BOOT_CFG: ");
+	show_boot_mode(readl(SRC_SBMR1));
+	/* SRC_GPR9 reflects what was actually booted off of if not 0
+	 * (ie if bmode was used) */
+	if (readl(SRC_GPR9)) {
+		printf("BMODE: ");
+		show_boot_mode(readl(SRC_GPR9));
+	}
+	printf("\n");
+	printf("Gateworks Corporation Copyright 2014\n");
+	if (info->model[0]) {
+		printf("Model: %s\n", info->model);
+		printf("MFGDate: %02x-%02x-%02x%02x\n",
+		       info->mfgdate[0], info->mfgdate[1],
+		       info->mfgdate[2], info->mfgdate[3]);
+		printf("Serial:%d\n", info->serial);
+	} else {
+		printf("Invalid EEPROM - board will not function fully\n");
+	}
+
+	return 0;
+}
+#endif
+
+/* Set gd->ram_size
+ */
+int dram_init(void)
+{
+	struct ventana_board_info *info = &ventana_info;
+
+	gd->ram_size = ((ulong)CONFIG_DDR_MB * 1024 * 1024);
+	if (info->model[0] && info->sdram_size > 0 && info->sdram_size < 9) {
+		int i = info->sdram_size;
+		gd->ram_size = 32*1024*1024;
+		while (--i)
+			gd->ram_size *= 2;
+	}
+
+	return 0;
+}
+
+/* initialize periperhals
+ */
+int board_init(void)
+{
+	int ret = 0;
+	struct iomuxc_base_regs *const iomuxc_regs
+		= (struct iomuxc_base_regs *)IOMUXC_BASE_ADDR;
+
+#ifdef CONFIG_CMD_NAND
+	setup_gpmi_nand();
+#endif
+
+	clrsetbits_le32(&iomuxc_regs->gpr[1],
+			IOMUXC_GPR1_OTG_ID_MASK,
+			IOMUXC_GPR1_OTG_ID_GPIO1);
+
+	imx_iomux_v3_setup_multiple_pads(usb_pads, ARRAY_SIZE(usb_pads));
+
+	/* address of linux boot parameters */
+	gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+
+#ifdef CONFIG_SYS_I2C_MXC
+	ret = setup_pmic_voltages();
+	if (ret)
+		return -1;
+#endif
+
+	setup_pcie();
+
+#ifdef CONFIG_CMD_SATA
+	setup_sata();
+#endif
+
+	if (!i2c_set_bus_num(0)) {
+		unsigned char buf[4];
+		if (!gsc_i2c_read(0x20, 14, 1, buf, 1)) {
+			printf("GSC:   v%d", buf[0]);
+			if (!gsc_i2c_read(0x20, 10, 1, buf, 4)) {
+				/* show firmware revision and CRC */
+				printf(" 0x%04x", buf[2] | buf[3]<<8);
+				/* show status register */
+				printf(" 0x%02x", buf[0]);
+				/* GSC watchdog timeout */
+				if (buf[0] & 0x40) {
+					printf(" WD_TIMEOUT");
+					/* clear flag */
+					buf[0] &= ~0x40;
+					gsc_i2c_write(0x20, 10, 1, buf, 1);
+				}
+			}
+			printf("\n");
+		}
+		if (!gsc_i2c_read(0x68, 0x00, 1, buf, 4))
+			printf("RTC:   %d\n",
+			       buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24);
+	}
+
+#ifdef CONFIG_CMD_GSC
+	/* if eFUSE not blown show GSC HWMON info */
+	if (!(readl(SRC_SBMR2) & 1<<4)) {
+		mdelay(1500);
+		do_gsc(NULL, 0, 0, NULL);
+	}
+#endif
+
+	return ret;
+}
+
+/* late init
+ */
+int misc_init_r(void)
+{
+	/* set env vars based on board model from EEPROM */
+	if (ventana_info.model[0]) {
+		char str[sizeof(ventana_info.model)];
+		char fdt[sizeof(ventana_info.model)+20];
+		char *p;
+		int i;
+		const char *prefix = "";
+
+		if (is_cpu_type(MXC_CPU_MX6Q))
+			prefix = "imx6q";
+		else if (is_cpu_type(MXC_CPU_MX6DL))
+			prefix = "imx6dl";
+
+		memset(str, 0, sizeof(str));
+		for (i = 0; i < (sizeof(ventana_info.model)-1) &&
+		     ventana_info.model[i]; i++)
+			str[i] = tolower(ventana_info.model[i]);
+		if (!getenv("model"))
+			setenv("model", str);
+		if (!getenv("fdt_file")) {
+			sprintf(fdt, "%s-%s.dtb", prefix, str);
+			setenv("fdt_file", fdt);
+		}
+		p = strchr(str, '-');
+		if (p) {
+			*p++ = 0;
+
+			setenv("model_base", str);
+			if (!getenv("fdt_file1")) {
+				sprintf(fdt, "%s-%s.dtb", prefix, str);
+				setenv("fdt_file1", fdt);
+			}
+			str[4] = 'x';
+			str[5] = 'x';
+			str[6] = 0;
+			if (!getenv("fdt_file2")) {
+				sprintf(fdt, "%s-%s.dtb", prefix, str);
+				setenv("fdt_file2", fdt);
+			}
+		}
+		get_mac("ethaddr", ventana_info.mac0);
+		get_mac("eth1addr", ventana_info.mac1);
+		sprintf(str, "%6d", ventana_info.serial);
+		setenv("serial#", str);
+		setup_board_gpio(getenv("model"));
+	}
+
+	/* generate a random eth mac if no EEPROM (1st boot - mfg mode) */
+	else {
+		u32 ethaddr_low, ethaddr_high;
+		char str[20];
+
+		/* use Device Unique ID bits 0-64 from eFUSE
+		 * (OCOTP_CFG1/OCOTP_CFG2) */
+		fuse_read(0, 1, &ethaddr_low);
+		fuse_read(0, 2, &ethaddr_high);
+
+		/*
+		 * setting the 2nd LSB in the most significant byte of
+		 * the address makes it a locally administered ethernet
+		 * address
+		 */
+		ethaddr_high &= 0xfeff;
+		ethaddr_high |= 0x0200;
+		sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
+			ethaddr_high >> 8, ethaddr_high & 0xff,
+			ethaddr_low >> 24, (ethaddr_low >> 16) & 0xff,
+			(ethaddr_low >> 8) & 0xff, ethaddr_low & 0xff);
+		printf("### Setting random MAC address = \"%s\"\n", str);
+		setenv("ethaddr", str);
+	}
+
+#ifdef CONFIG_CMD_BMODE
+	add_board_boot_modes(board_boot_modes);
+#endif
+
+	/* disable GSC boot watchdog
+	 *
+	 *  The Gateworks System Controller implements a boot
+	 *  watchdog (always enabled) to cover things like ERR006282 which can
+	 *  lead to random boot failures.
+	 */
+	if (!i2c_set_bus_num(0)) {
+		unsigned char val;
+		if (!gsc_i2c_read(0x20, 1, 1, &val, 1)) {
+			val |= 0x80;
+			if (gsc_i2c_write(0x20, 1, 1, &val, 1))
+				printf("Error: could not disable GSC Watchdog\n");
+		} else {
+			printf("Error: could not disable GSC Watchdog\n");
+		}
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+void ft_board_setup(void *blob, bd_t *bd)
+{
+	struct ventana_board_info *info = &ventana_info;
+	struct node_info nodes[] = {
+		{ "sst,w25q256",          MTD_DEV_TYPE_NOR, },  /* SPI flash */
+		{ "fsl,imx6q-gpmi-nand",  MTD_DEV_TYPE_NAND, }, /* NAND flash */
+	};
+	const char *model = getenv("model");
+
+	if (getenv("fdt_noauto")) {
+		printf("   Skiping ft_board_setup (fdt_noauto defined)\n");
+		return;
+	}
+
+	/* MTD partitions
+	 * Update partition nodes using info from mtdparts env var
+	 */
+	printf("   Updating MTD partitions...\n");
+	fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
+
+	if (!model) {
+		printf("invalid board info: Leaving FDT fully enabled\n");
+		return;
+	}
+	printf("   Adjusting FDT per EEPROM for %s...\n", model);
+
+	/* Note that fdt_fixup_ethernet is called in arm/lib/bootm before this
+	 * which sets mac-address and local-mac-address properties of
+	 * ethernet<n> aliases to ethaddr...eth<n>addr env
+	 */
+
+	/* board serial number */
+	fdt_setprop(blob, 0, "system-serial", getenv("serial#"),
+		    strlen(getenv("serial#") + 1));
+
+	/* board (model contains model from device-tree) */
+	fdt_setprop(blob, 0, "board", info->model,
+		    strlen((const char *)info->model) + 1);
+
+	/* Peripheral Config */
+	if (!info->config_eth0)
+		fdt_del_node_and_alias(blob, "ethernet0");
+	if (!info->config_eth1)
+		fdt_del_node_and_alias(blob, "ethernet1");
+	if (!info->config_hdmi_out)
+		fdt_del_node_and_alias(blob, "hdmi_out");
+	if (!info->config_sata)
+		fdt_del_node_and_alias(blob, "ahci0");
+	if (!info->config_pcie)
+		fdt_del_node_and_alias(blob, "pcie");
+	if (!info->config_ssi0)
+		fdt_del_node_and_alias(blob, "ssi0");
+	if (!info->config_ssi1)
+		fdt_del_node_and_alias(blob, "ssi1");
+	if (!info->config_lcd)
+		fdt_del_node_and_alias(blob, "lcd0");
+	if (!info->config_lvds0)
+		fdt_del_node_and_alias(blob, "lvds0");
+	if (!info->config_lvds1)
+		fdt_del_node_and_alias(blob, "lvds1");
+	if (!info->config_usb0)
+		fdt_del_node_and_alias(blob, "usb0");
+	if (!info->config_usb1)
+		fdt_del_node_and_alias(blob, "usb1");
+	if (!info->config_sd0)
+		fdt_del_node_and_alias(blob, "usdhc0");
+	if (!info->config_sd1)
+		fdt_del_node_and_alias(blob, "usdhc1");
+	if (!info->config_sd2)
+		fdt_del_node_and_alias(blob, "usdhc2");
+	if (!info->config_sd3)
+		fdt_del_node_and_alias(blob, "usdhc3");
+	if (!info->config_uart0)
+		fdt_del_node_and_alias(blob, "serial0");
+	if (!info->config_uart1)
+		fdt_del_node_and_alias(blob, "serial1");
+	if (!info->config_uart2)
+		fdt_del_node_and_alias(blob, "serial2");
+	if (!info->config_uart3)
+		fdt_del_node_and_alias(blob, "serial3");
+	if (!info->config_uart4)
+		fdt_del_node_and_alias(blob, "serial4");
+	if (!info->config_ipu0)
+		fdt_del_node_and_alias(blob, "ipu0");
+	if (!info->config_ipu1)
+		fdt_del_node_and_alias(blob, "ipu1");
+	if (!info->config_flexcan)
+		fdt_del_node_and_alias(blob, "can0");
+	if (!info->config_mipi_dsi)
+		fdt_del_node_and_alias(blob, "mipi_dsi");
+	if (!info->config_mipi_csi)
+		fdt_del_node_and_alias(blob, "mipi_csi");
+	if (!info->config_tzasc0)
+		fdt_del_node_and_alias(blob, "tzasc0");
+	if (!info->config_tzasc1)
+		fdt_del_node_and_alias(blob, "tzasc1");
+	if (!info->config_i2c0)
+		fdt_del_node_and_alias(blob, "i2c0");
+	if (!info->config_i2c1)
+		fdt_del_node_and_alias(blob, "i2c1");
+	if (!info->config_i2c2)
+		fdt_del_node_and_alias(blob, "i2c2");
+	if (!info->config_vpu)
+		fdt_del_node_and_alias(blob, "vpu");
+	if (!info->config_csi0)
+		fdt_del_node_and_alias(blob, "csi0");
+	if (!info->config_csi1)
+		fdt_del_node_and_alias(blob, "csi1");
+	if (!info->config_caam)
+		fdt_del_node_and_alias(blob, "caam");
+	if (!info->config_espci0)
+		fdt_del_node_and_alias(blob, "spi0");
+	if (!info->config_espci1)
+		fdt_del_node_and_alias(blob, "spi1");
+	if (!info->config_espci2)
+		fdt_del_node_and_alias(blob, "spi2");
+	if (!info->config_espci3)
+		fdt_del_node_and_alias(blob, "spi3");
+	if (!info->config_espci4)
+		fdt_del_node_and_alias(blob, "spi4");
+	if (!info->config_espci5)
+		fdt_del_node_and_alias(blob, "spi5");
+	if (!info->config_hdmi_in)
+		fdt_del_node_and_alias(blob, "hdmi_in");
+	if (!info->config_vid_out)
+		fdt_del_node_and_alias(blob, "cvbs_out");
+	if (!info->config_vid_in)
+		fdt_del_node_and_alias(blob, "cvbs_in");
+	if (!info->config_nand)
+		fdt_del_node_and_alias(blob, "nand");
+	if (!info->config_gps)
+		fdt_del_node_and_alias(blob, "pps");
+}
+#endif /* defined(CONFIG_OF_FLAT_TREE) && defined(CONFIG_OF_BOARD_SETUP) */
+
diff --git a/board/gateworks/gw_ventana/gw_ventana.cfg b/board/gateworks/gw_ventana/gw_ventana.cfg
new file mode 100644
index 0000000..4e07528
--- /dev/null
+++ b/board/gateworks/gw_ventana/gw_ventana.cfg
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright (C) 2013 Gateworks Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Refer doc/README.imximage for more details about how-to configure
+ * and create imximage boot image
+ *
+ * The syntax is taken as close as possible with the kwbimage
+ */
+
+/* image version */
+IMAGE_VERSION 2
+
+/*
+ * Boot Device : one of
+ * spi, sd, nand, sata
+ */
+#ifdef CONFIG_SPI_FLASH
+BOOT_FROM      spi
+#else
+BOOT_FROM      nand
+#endif
+
+#define __ASSEMBLY__
+#include <config.h>
+#include "asm/arch/mx6-ddr.h"
+#include "asm/arch/iomux.h"
+#include "asm/arch/crm_regs.h"
+
+/* Memory configuration (size is overridden via eeprom config) */
+#include "ddr-setup.cfg"
+#if defined(CONFIG_MX6Q) && CONFIG_DDR_MB == 1024
+  #include "1066mhz_4x128mx16.cfg"
+#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 1024
+  #include "800mhz_4x128mx16.cfg"
+#elif defined(CONFIG_MX6DL) && CONFIG_DDR_MB == 512
+  #include "800mhz_2x128mx16.cfg"
+#else
+  #error "Unsupported CPU/Memory configuration"
+#endif
+#include "clocks.cfg"
diff --git a/board/gateworks/gw_ventana/ventana_eeprom.h b/board/gateworks/gw_ventana/ventana_eeprom.h
new file mode 100644
index 0000000..ea6524a
--- /dev/null
+++ b/board/gateworks/gw_ventana/ventana_eeprom.h
@@ -0,0 +1,107 @@ 
+/*
+ * ventana_eeprom.h - Gateworks Ventana EEPROM Configuration
+ * v1.00
+ */
+#ifndef _VENTANA_EEPROM_
+#define _VENTANA_EEPROM_
+
+struct ventana_board_info {
+	u8 mac0[6];          /* 0x00: MAC1 */
+	u8 mac1[6];          /* 0x06: MAC2 */
+	u8 res0[12];         /* 0x0C: reserved */
+	u32 serial;          /* 0x18: Serial Number (read only) */
+	u8 res1[4];          /* 0x1C: reserved */
+	u8 mfgdate[4];       /* 0x20: MFG date (read only) */
+	u8 res2[7];          /* 0x24 */
+	/* sdram config */
+	u8 sdram_size;       /* 0x2B: enum (512,1024,2048) MB */
+	u8 sdram_speed;      /* 0x2C: enum (100,133,166,200,267,333,400) MHz */
+	u8 sdram_width;      /* 0x2D: enum (32,64) bit */
+	/* cpu config */
+	u8 cpu_speed;        /* 0x2E: enum (800,1000,1200) MHz */
+	u8 cpu_type;         /* 0x2F: enum (imx6q,imx6d,imx6dl,imx6s) */
+	u8 model[16];        /* 0x30: model string */
+	/* FLASH config */
+	u8 nand_flash_size;  /* 0x40: enum (4,8,16,32,64,128) MB */
+	u8 spi_flash_size;   /* 0x41: enum (4,8,16,32,64,128) MB */
+
+	/* Config1: SoC Peripherals */
+	u8 config_eth0:1;    /* 0: 0x42 */
+	u8 config_eth1:1;    /* 1 */
+	u8 config_hdmi_out:1;/* 2 */
+	u8 config_sata:1;    /* 3 */
+	u8 config_pcie:1;    /* 4 */
+	u8 config_ssi0:1;    /* 5 */
+	u8 config_ssi1:1;    /* 6 */
+	u8 config_lcd:1;     /* 7 */
+
+	u8 config_lvds0:1;   /* 0: 0x43 */
+	u8 config_lvds1:1;   /* 1 */
+	u8 config_usb0:1;    /* 2 (USB EHCI) */
+	u8 config_usb1:1;    /* 3 (USB OTG) */
+	u8 config_sd0:1;     /* 4 */
+	u8 config_sd1:1;     /* 5 */
+	u8 config_sd2:1;     /* 6 */
+	u8 config_sd3:1;     /* 7 */
+
+	u8 config_uart0:1;   /* 0: 0x44 */
+	u8 config_uart1:1;   /* 1 */
+	u8 config_uart2:1;   /* 2 */
+	u8 config_uart3:1;   /* 3 */
+	u8 config_uart4:1;   /* 4 */
+	u8 config_ipu0:1;    /* 5 */
+	u8 config_ipu1:1;    /* 6 */
+	u8 config_flexcan:1; /* 7 */
+
+	u8 config_mipi_dsi:1;/* 0: 0x45 */
+	u8 config_mipi_csi:1;/* 1 */
+	u8 config_tzasc0:1;  /* 2 */
+	u8 config_tzasc1:1;  /* 3 */
+	u8 config_i2c0:1;    /* 4 */
+	u8 config_i2c1:1;    /* 5 */
+	u8 config_i2c2:1;    /* 6 */
+	u8 config_vpu:1;     /* 7 */
+
+	u8 config_csi0:1;    /* 0: 0x46 */
+	u8 config_csi1:1;    /* 1 */
+	u8 config_caam:1;    /* 2 */
+	u8 config_mezz:1;    /* 3 */
+	u8 config_res1:1;    /* 4 */
+	u8 config_res2:1;    /* 5 */
+	u8 config_res3:1;    /* 6 */
+	u8 config_res4:1;    /* 7 */
+
+	u8 config_espci0:1;  /* 0: 0x47 */
+	u8 config_espci1:1;  /* 1 */
+	u8 config_espci2:1;  /* 2 */
+	u8 config_espci3:1;  /* 3 */
+	u8 config_espci4:1;  /* 4 */
+	u8 config_espci5:1;  /* 5 */
+	u8 config_res5:1;    /* 6 */
+	u8 config_res6:1;    /* 7 */
+
+	/* Config2: Other Peripherals */
+	u8 config_gps:1;     /* 0: 0x48 */
+	u8 config_spifl0:1;  /* 1 */
+	u8 config_spifl1:1;  /* 2 */
+	u8 config_gspbatt:1; /* 3 */
+	u8 config_hdmi_in:1; /* 4 */
+	u8 config_vid_out:1; /* 5 */
+	u8 config_vid_in:1;  /* 6 */
+	u8 config_nand:1;    /* 7 */
+
+	u8 config_res8:1;    /* 0: 0x49 */
+	u8 config_res9:1;    /* 1 */
+	u8 config_res10:1;   /* 2 */
+	u8 config_res11:1;   /* 3 */
+	u8 config_res12:1;   /* 4 */
+	u8 config_res13:1;   /* 5 */
+	u8 config_res14:1;   /* 6 */
+	u8 config_res15:1;   /* 7 */
+
+	u8 res3[4];          /* 0x4A */
+
+	u8 chksum[2];        /* 0x4E */
+};
+
+#endif
diff --git a/boards.cfg b/boards.cfg
index a8336cc..7784b3a 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -295,6 +295,7 @@  Active  arm         armv7          mx6         -               udoo		   udoo_qua
 Active  arm         armv7          mx6         -               wandboard           wandboard_dl                         wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024                                                  Fabio Estevam <fabio.estevam@freescale.com>
 Active  arm         armv7          mx6         -               wandboard           wandboard_quad                       wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q2g.cfg,MX6Q,DDR_MB=2048                                                  Fabio Estevam <fabio.estevam@freescale.com>
 Active  arm         armv7          mx6         -               wandboard           wandboard_solo                       wandboard:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6s.cfg,MX6S,DDR_MB=512                                                     Fabio Estevam <fabio.estevam@freescale.com>
+Active  arm         armv7          mx6         barco           titanium            titanium                             titanium:IMX_CONFIG=board/barco/titanium/imximage.cfg                                                                         Stefan Roese <sr@denx.de>
 Active  arm         armv7          mx6         boundary        nitrogen6x          mx6qsabrelite                        nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6q.cfg,MX6Q,DDR_MB=1024,SABRELITE                                         Eric Nelson <eric.nelson@boundarydevices.com>
 Active  arm         armv7          mx6         boundary        nitrogen6x          nitrogen6dl                          nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024                                                 Eric Nelson <eric.nelson@boundarydevices.com>
 Active  arm         armv7          mx6         boundary        nitrogen6x          nitrogen6dl2g                        nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl2g.cfg,MX6DL,DDR_MB=2048                                               Eric Nelson <eric.nelson@boundarydevices.com>
@@ -308,7 +309,11 @@  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         barco           titanium            titanium                             titanium:IMX_CONFIG=board/barco/titanium/imximage.cfg                                                                         Stefan Roese <sr@denx.de>
+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          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          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         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
new file mode 100644
index 0000000..17877ed
--- /dev/null
+++ b/include/configs/gw_ventana.h
@@ -0,0 +1,409 @@ 
+/*
+ * Copyright (C) 2013 Gateworks Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include "mx6_common.h"
+#define CONFIG_MX6
+#define CONFIG_DISPLAY_CPUINFO   /* display cpu info */
+#define CONFIG_DISPLAY_BOARDINFO /* display board info */
+
+#define CONFIG_MACH_TYPE	4520   /* Gateworks Ventana Platform */
+
+#include <asm/arch/imx-regs.h>
+#include <asm/imx-common/gpio.h>
+
+/* ATAGs */
+#define CONFIG_CMDLINE_TAG
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
+#define CONFIG_SERIAL_TAG
+#define CONFIG_REVISION_TAG
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		(10 * 1024 * 1024)
+
+/* Init Functions */
+#define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_MISC_INIT_R
+
+/* GPIO */
+#define CONFIG_MXC_GPIO
+
+/* Serial */
+#define CONFIG_MXC_UART
+#define CONFIG_MXC_UART_BASE	       UART2_BASE
+
+#ifdef CONFIG_SPI_FLASH
+
+/* SPI */
+#define CONFIG_CMD_SF
+#ifdef CONFIG_CMD_SF
+  #define CONFIG_MXC_SPI
+  #define CONFIG_SPI_FLASH_MTD
+  #define CONFIG_SPI_FLASH_BAR
+  #define CONFIG_SPI_FLASH_WINBOND
+  #define CONFIG_SPI_FLASH_WINBOND_ERASESIZE 64*1024  /* 4,32,64K for W26Q256 */
+  #define CONFIG_SF_DEFAULT_BUS              0
+  #define CONFIG_SF_DEFAULT_CS               (0|(IMX_GPIO_NR(3, 19)<<8))
+					     /* GPIO 3-19 (21248) */
+  #define CONFIG_SF_DEFAULT_SPEED            30000000
+  #define CONFIG_SF_DEFAULT_MODE             (SPI_MODE_0)
+#endif
+
+/* Flattened Image Tree Suport */
+#define CONFIG_FIT
+#define CONFIG_FIT_VERBOSE
+
+#else
+/* Enable NAND support */
+#define CONFIG_CMD_TIME
+#define CONFIG_CMD_NAND
+#define CONFIG_CMD_NAND_TRIMFFS
+#ifdef CONFIG_CMD_NAND
+  #define CONFIG_NAND_MXS
+  #define CONFIG_SYS_MAX_NAND_DEVICE	1
+  #define CONFIG_SYS_NAND_BASE		0x40000000
+  #define CONFIG_SYS_NAND_5_ADDR_CYCLE
+  #define CONFIG_SYS_NAND_ONFI_DETECTION
+
+  /* DMA stuff, needed for GPMI/MXS NAND support */
+  #define CONFIG_APBH_DMA
+  #define CONFIG_APBH_DMA_BURST
+  #define CONFIG_APBH_DMA_BURST8
+#endif
+
+#endif /* CONFIG_SPI_FLASH */
+
+/* I2C Configs */
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C
+#define CONFIG_SYS_I2C_MXC
+#define CONFIG_SYS_I2C_SPEED		  100000
+
+/* MMC Configs */
+#define CONFIG_FSL_ESDHC
+#define CONFIG_FSL_USDHC
+#define CONFIG_SYS_FSL_ESDHC_ADDR      0
+#define CONFIG_SYS_FSL_USDHC_NUM       1
+#define CONFIG_MMC
+#define CONFIG_CMD_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_BOUNCE_BUFFER
+
+/* Filesystem support */
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_FAT
+#define CONFIG_CMD_UBIFS
+#define CONFIG_DOS_PARTITION
+
+/* Network config - Allow larger/faster download for TFTP/NFS */
+#define CONFIG_IP_DEFRAG
+#define CONFIG_TFTP_BLOCKSIZE 4096
+#define CONFIG_NFS_READ_SIZE  4096
+
+#ifdef CONFIG_MX6Q
+#define CONFIG_CMD_SATA
+#endif
+
+/*
+ * SATA Configs
+ */
+#ifdef CONFIG_CMD_SATA
+  #define CONFIG_DWC_AHSATA
+  #define CONFIG_SYS_SATA_MAX_DEVICE	1
+  #define CONFIG_DWC_AHSATA_PORT_ID	0
+  #define CONFIG_DWC_AHSATA_BASE_ADDR	SATA_ARB_BASE_ADDR
+  #define CONFIG_LBA48
+  #define CONFIG_LIBATA
+#endif
+
+/* Various command support */
+#include <config_cmd_default.h>
+#undef CONFIG_CMD_IMLS
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_NET
+#define CONFIG_CMD_BMODE         /* set eFUSE shadow for a boot dev and reset */
+#define CONFIG_CMD_HDMIDETECT    /* detect HDMI output device */
+#define CONFIG_CMD_SETEXPR
+#define CONFIG_CMD_BOOTZ
+#define CONFIG_CMD_GSC
+#define CONFIG_CMD_UBI
+#define CONFIG_RBTREE
+#define CONFIG_LZO
+#define CONFIG_CMD_FUSE          /* eFUSE read/write support */
+#ifdef CONFIG_CMD_FUSE
+#define CONFIG_MXC_OCOTP
+#endif
+
+
+/* Ethernet support */
+#define CONFIG_FEC_MXC
+#define CONFIG_MII
+#define IMX_FEC_BASE             ENET_BASE_ADDR
+#define CONFIG_FEC_XCV_TYPE      RGMII
+#define CONFIG_ETHPRIME          "FEC"
+#define CONFIG_FEC_MXC_PHYADDR   0
+#define CONFIG_PHYLIB
+#define CONFIG_ARP_TIMEOUT       200UL
+
+/* USB Configs */
+#define CONFIG_CMD_USB
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_MX6
+#define CONFIG_USB_STORAGE
+#define CONFIG_USB_HOST_ETHER
+#define CONFIG_USB_ETHER_ASIX
+#define CONFIG_USB_ETHER_SMSC95XX
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
+#define CONFIG_EHCI_HCD_INIT_AFTER_RESET  /* For OTG port */
+#define CONFIG_MXC_USB_PORTSC     (PORT_PTS_UTMI | PORT_PTS_PTW)
+#define CONFIG_MXC_USB_FLAGS      0
+#define CONFIG_USB_KEYBOARD
+#define CONFIG_MV_UDC
+#define CONFIG_USBD_HS
+#define CONFIG_USB_GADGET_DUALSPEED
+#define CONFIG_USB_ETHER
+#define CONFIG_USB_ETH_CDC
+#define CONFIG_NETCONSOLE
+#define CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP
+#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY 1200
+
+/* Framebuffer and LCD */
+#define CONFIG_VIDEO
+#define CONFIG_VIDEO_IPUV3
+#define CONFIG_CFB_CONSOLE
+#define CONFIG_VGA_AS_SINGLE_DEVICE
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
+#define CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
+#define CONFIG_VIDEO_BMP_RLE8
+#define CONFIG_SPLASH_SCREEN
+#define CONFIG_BMP_16BPP
+#define CONFIG_VIDEO_LOGO
+#define CONFIG_IPUV3_CLK          260000000
+#define CONFIG_CONSOLE_MUX
+#define CONFIG_IMX_HDMI
+
+/* serial console (ttymxc1,115200) */
+#define CONFIG_CONS_INDEX              1
+#define CONFIG_BAUDRATE                115200
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT	             "Ventana > "
+#define CONFIG_SYS_CBSIZE	             1024
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_HWCONFIG
+
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS	           16
+#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
+
+/* Memory configuration */
+#define CONFIG_SYS_MEMTEST_START       0x10000000
+#define CONFIG_SYS_MEMTEST_END	       0x10010000
+#define CONFIG_SYS_MEMTEST_SCRATCH     0x10800000
+#define CONFIG_SYS_TEXT_BASE	         0x17800000
+#define CONFIG_SYS_LOAD_ADDR           0x12000000
+
+/* Physical Memory Map */
+#define CONFIG_NR_DRAM_BANKS           1
+#define PHYS_SDRAM                     MMDC0_ARB_BASE_ADDR
+#define CONFIG_SYS_SDRAM_BASE          PHYS_SDRAM
+#define CONFIG_SYS_INIT_RAM_ADDR       IRAM_BASE_ADDR
+#define CONFIG_SYS_INIT_RAM_SIZE       IRAM_SIZE
+
+#define CONFIG_SYS_INIT_SP_OFFSET \
+	(CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
+
+/* FLASH and environment organization */
+#define CONFIG_SYS_NO_FLASH  /* no NOR flash */
+
+/*
+ * MTD Command for mtdparts
+ */
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_SPI_FLASH
+#define MTDIDS_DEFAULT    "nor0=nor"
+#define MTDPARTS_DEFAULT  "mtdparts=nor:512k(uboot),64k(env),2m(kernel),-(rootfs)"
+#else
+#define MTDIDS_DEFAULT    "nand0=nand"
+#define MTDPARTS_DEFAULT  "mtdparts=nand:16m(uboot),1m(env),-(rootfs)"
+#endif
+
+/* Persistent Environment Config */
+#define CONFIG_ENV_OVERWRITE    /* allow to overwrite serial and ethaddr */
+#ifdef CONFIG_SPI_FLASH
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#else
+#define CONFIG_ENV_IS_IN_NAND
+#endif
+#if defined(CONFIG_ENV_IS_IN_MMC)
+  #define CONFIG_ENV_OFFSET              (6 * 64 * 1024)
+  #define CONFIG_ENV_SIZE                (8 * 1024)
+  #define CONFIG_SYS_MMC_ENV_DEV         0
+#elif defined(CONFIG_ENV_IS_IN_NAND)
+  #define CONFIG_ENV_OFFSET              (16 << 20)
+  #define CONFIG_ENV_SECT_SIZE           (128 << 10)
+  #define CONFIG_ENV_SIZE                CONFIG_ENV_SECT_SIZE
+  #define CONFIG_ENV_OFFSET_REDUND       (CONFIG_ENV_OFFSET + (512 << 10))
+  #define CONFIG_ENV_SIZE_REDUND         CONFIG_ENV_SIZE
+#elif defined(CONFIG_ENV_IS_IN_SPI_FLASH)
+  #define CONFIG_ENV_OFFSET              (512 * 1024)
+  #define CONFIG_ENV_SECT_SIZE           (64 * 1024)
+  #define CONFIG_ENV_SIZE                (8 * 1024)
+  #define CONFIG_ENV_SPI_BUS             CONFIG_SF_DEFAULT_BUS
+  #define CONFIG_ENV_SPI_CS              CONFIG_SF_DEFAULT_CS
+  #define CONFIG_ENV_SPI_MODE            CONFIG_SF_DEFAULT_MODE
+  #define CONFIG_ENV_SPI_MAX_HZ          CONFIG_SF_DEFAULT_SPEED
+#endif
+
+/* Environment */
+#define CONFIG_BOOTDELAY          3
+#define CONFIG_LOADADDR           CONFIG_SYS_LOAD_ADDR
+#define CONFIG_IPADDR             192.168.1.1
+#define CONFIG_SERVERIP           192.168.1.146
+
+#define CONFIG_EXTRA_ENV_SETTINGS_COMMON \
+	"console=ttymxc1\0" \
+	"bootdevs=usb mmc sata flash\0" \
+	"hwconfig=rs232;dio0:mode=gpio;dio1:mode=gpio;dio2:mode=gpio;dio3:mode=gpio\0" \
+	"video=\0" \
+	\
+	"mtdparts=" MTDPARTS_DEFAULT "\0" \
+	"mtdids=" MTDIDS_DEFAULT "\0" \
+	\
+	"fdt_high=0xffffffff\0" \
+	"fdt_addr=0x18000000\0" \
+	"loadfdt=" \
+		"if ${fsload} ${fdt_addr} boot/${fdt_file}; then " \
+			"echo Loaded DTB from boot/${fdt_file}; " \
+		"elif ${fsload} ${fdt_addr} boot/${fdt_file1}; then " \
+			"echo Loaded DTB from boot/${fdt_file1}; " \
+		"elif ${fsload} ${fdt_addr} boot/${fdt_file2}; then " \
+				"echo Loaded DTB from boot/${fdt_file2}; " \
+		"fi\0" \
+	\
+	"script=boot/6x_bootscript-ventana\0" \
+	"loadscript=" \
+		"if ${fsload} ${loadaddr} ${script}; then " \
+			"source; " \
+		"fi\0" \
+	\
+	"uimage=boot/uImage\0" \
+	"mmc_root=/dev/mmcblk0p1 rootfstype=ext4 rootwait rw\0" \
+	"mmc_boot=" \
+		"setenv fsload 'ext2load mmc 0:1'; " \
+		"mmc dev 0 && mmc rescan && " \
+		"run loadscript; " \
+		"if ${fsload} ${loadaddr} ${uimage}; then " \
+			"setenv bootargs console=${console},${baudrate} " \
+				"root=/dev/mmcblk0p1 rootfstype=ext4 rootwait rw ${video} ${extra}; " \
+			"if run loadfdt && fdt addr ${fdt_addr}; then " \
+				"bootm ${loadaddr} - ${fdt_addr}; " \
+			"else " \
+				"bootm; " \
+			"fi; " \
+		"fi\0" \
+	\
+	"sata_boot=" \
+		"setenv fsload 'ext2load sata 0:1'; sata init && " \
+		"run loadscript; " \
+		"if ${fsload} ${loadaddr} ${uimage}; then " \
+			"setenv bootargs console=${console},${baudrate} " \
+				"root=/dev/sda1 rootfstype=ext4 rootwait rw ${video} ${extra}; " \
+			"if run loadfdt && fdt addr ${fdt_addr}; then " \
+				"bootm ${loadaddr} - ${fdt_addr}; " \
+			"else " \
+				"bootm; " \
+			"fi; " \
+		"fi\0" \
+	"usb_boot=" \
+		"setenv fsload 'ext2load usb 0:1'; usb start && usb dev 0 && " \
+		"run loadscript; " \
+		"if ${fsload} ${loadaddr} ${uimage}; then " \
+			"setenv bootargs console=${console},${baudrate} " \
+				"root=/dev/sda1 rootfstype=ext4 rootwait rw ${video} ${extra}; " \
+			"if run loadfdt && fdt addr ${fdt_addr}; then " \
+				"bootm ${loadaddr} - ${fdt_addr}; " \
+			"else " \
+				"bootm; " \
+			"fi; " \
+		"fi\0"
+
+#ifdef CONFIG_SPI_FLASH
+	#define CONFIG_EXTRA_ENV_SETTINGS \
+	CONFIG_EXTRA_ENV_SETTINGS_COMMON \
+	"image_os=ventana/openwrt-imx6-imx6q-gw5400-a-squashfs.bin\0" \
+	"image_uboot=ventana/u-boot_spi.imx\0" \
+	\
+	"spi_koffset=0x90000\0" \
+	"spi_klen=0x200000\0" \
+	\
+	"spi_updateuboot=echo Updating uboot from ${serverip}:${image_uboot} ...; " \
+		"tftpboot ${loadaddr} ${image_uboot} && " \
+		"sf probe && sf erase 0 80000 && sf write ${loadaddr} 400 ${filesize}\0"	\
+	"spi_update=echo Updating OS from ${serverip}:${image_os} to ${spi_koffset} ...; " \
+		"tftp ${loadaddr} ${image_os} && " \
+		"sf probe && sf update ${loadaddr} ${spi_koffset} ${filesize}\0" \
+	\
+	"flash_boot=" \
+		"if sf probe && sf read ${loadaddr} ${spi_koffset} ${spi_klen}; then " \
+			"setenv bootargs console=${console},${baudrate} " \
+				"root=/dev/mtdblock3 rootfstype=squashfs,jffs2 ${video} ${extra}; " \
+			"bootm; " \
+		"fi\0"
+#else
+	#define CONFIG_EXTRA_ENV_SETTINGS \
+	CONFIG_EXTRA_ENV_SETTINGS_COMMON \
+	"image_rootfs=openwrt-imx6-ventana-rootfs.ubi\0" \
+	\
+	"nand_update=echo Updating NAND from ${serverip}:${image_rootfs} ...; " \
+		"tftp ${loadaddr} ${image_rootfs} && " \
+		"nand erase.part rootfs && " \
+		"nand write ${loadaddr} rootfs ${filesize}\0" \
+	\
+	"flash_boot=" \
+		"setenv fsload 'ubifsload'; " \
+		"ubi part rootfs && ubifsmount ubi0:rootfs; " \
+		"run loadscript; " \
+		"if ${fsload} ${loadaddr} ${uimage}; then " \
+			"setenv bootargs console=${console},${baudrate} " \
+				"root=ubi0:rootfs ubi.mtd=2 rootfstype=ubifs ${video} ${extra}; " \
+			"if run loadfdt && fdt addr ${fdt_addr}; then " \
+				"ubifsumount; bootm ${loadaddr} - ${fdt_addr}; " \
+			"else " \
+				"ubifsumount; bootm; " \
+			"fi; " \
+		"fi\0"
+#endif
+
+#define CONFIG_BOOTCOMMAND \
+	"for btype in ${bootdevs}; do " \
+		"echo; echo Attempting ${btype} boot...; " \
+		"if run ${btype}_boot; then; fi; " \
+	"done"
+
+/* Device Tree Support */
+#define CONFIG_OF_BOARD_SETUP
+#define CONFIG_OF_LIBFDT
+#define CONFIG_FDT_FIXUP_PARTITIONS
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+  #define CONFIG_CMD_CACHE
+#endif
+
+#endif			       /* __CONFIG_H */