avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
if TARGET_GW_VENTANA
config SYS_BOARD
default "gw_ventana"
config SYS_VENDOR
default "gateworks"
config SYS_CONFIG_NAME
default "gw_ventana"
endif

View File

@@ -0,0 +1,6 @@
GW_VENTANA BOARD
M: Tim Harvey <tharvey@gateworks.com>
S: Maintained
F: board/gateworks/gw_ventana/
F: include/configs/gw_ventana.h
F: configs/gwventana_defconfig

View File

@@ -0,0 +1,11 @@
#
# 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 gsc.o eeprom.o common.o
obj-$(CONFIG_SPL_BUILD) += gw_ventana_spl.o

View File

@@ -0,0 +1,315 @@
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.
The entire Ventana product family (http://www.gateworks.com/product#ventana)
is supported by a single bootloader build by using a common SPL and U-Boot
that dynamically determines the characterstics of the board at runtime via
information from an EEPROM on the board programmed at the factory and supports
all of the various boot mediums available.
1. Secondary Program Loader (SPL)
---------------------------------
The i.MX6 has a BOOT ROM PPL (Primary Program Loader) which supports loading
an executable image from various boot devices.
The Gateworks Ventana board config uses an SPL build configuration. This
will build the following artifacts from U-Boot source:
- SPL - Secondary Program Loader that the i.MX6 BOOT ROM (Primary Program
Loader) boots. This detects CPU/DRAM configuration, configures
The DRAM controller, loads u-boot.img from the detected boot device,
and jumps to it. As this is booted from the PPL, it has an IVT/DCD
table.
- u-boot.img - The main U-Boot core which is u-boot.bin with a image header.
2. Build
--------
To build U-Boot for the Gateworks Ventana product family:
make gwventana_config
make
3. Boot source:
---------------
The Gateworks Ventana boards support booting from NAND or micro-SD depending
on the board model. The IMX6 BOOT ROM will choose a boot media based on eFUSE
settings programmed at the factory.
Boards with NAND flash will always boot from NAND, and NAND-less boards will
always boot from micro-SD. However, it is possible to use the U-Boot bmode
command (or the technique it uses) to essentially bootstrap to another boot
media at runtime.
3.1. boot from NAND
-------------------
The i.MX6 BOOT ROM expects some structures that provide details of NAND layout
and bad block information (referred to as 'bootstreams') which are replicated
multiple times in NAND. The number of replications and their spacing (referred
to as search stride) is configurable through board strapping options and/or
eFUSE settings (BOOT_SEARCH_COUNT / Pages in block from BOOT_CFG2). In
addition, the i.MX6 BOOT ROM Flash Configuration Block (FCB) supports two
copies of a bootloader in flash in the case that a bad block has corrupted one.
The Freescale 'kobs-ng' application from the Freescale LTIB BSP, which runs
under Linux and operates on an MTD partition, must be used to program the
bootstream in order to setup this flash structure correctly.
The Gateworks Ventana boards with NAND flash have been factory programmed
such that their eFUSE settings expect 2 copies of the boostream (this is
specified by providing kobs-ng with the --search_exponent=1 argument). Once in
Linux with MTD support for the NAND on /dev/mtd0 you can program the SPL
with:
kobs-ng init -v -x --search_exponent=1 SPL
The kobs-ng application uses an imximage which contains the Image Vector Table
(IVT) and Device Configuration Data (DCD) structures that the i.MX6 BOOT ROM
requires to boot. The kobs-ng adds the Firmware Configuration Block (FCB) and
Discovered Bad Block Table (DBBT). The SPL build artifact from U-Boot is
an imximage.
The u-boot.img, which is the non SPL U-Boot binary appended to a U-Boot image
header must be programmed in the NAND flash boot device at an offset hard
coded in the SPL. For the Ventana boards, this has been chosen to be 14MB.
The image can be programmed from either U-Boot or Linux:
U-Boot:
Ventana > setenv mtdparts mtdparts=nand:14m(spl),2m(uboot),1m(env),-(rootfs)
Ventana > tftp ${loadaddr} u-boot.img && nand erase.part uboot && \
nand write ${loadaddr} uboot ${filesize}
Linux:
nandwrite /dev/mtd1 u-boot.img
The above assumes the default Ventana partitioning scheme which is configured
via the mtdparts env var:
- spl: 14MB
- uboot: 2M
- env: 1M
- rootfs: the rest
This information is taken from:
http://trac.gateworks.com/wiki/ventana/bootloader#nand
More details about the i.MX6 BOOT ROM can be found in the IMX6 reference manual.
3.1. boot from micro-SD
-----------------------
When the IMX6 eFUSE settings have been factory programmed to boot from
micro-SD the SPL will be loaded from offset 0x400 (1KB). Once the SPL is
booted, it will load and execute U-Boot (u-boot.img) from offset 69KB
on the micro-SD (defined by CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR).
While it is technically possible to enable the SPL to be able to load
U-Boot from a file on a FAT/EXT filesystem on the micro-SD, we chose to
use raw micro-SD access to keep the code-size and boot time of the SPL down.
For these reasons a micro-SD that will be used as an IMX6 primary boot
device must be carefully partitioned and prepared.
The following shell commands are executed on a Linux host (adjust DEV to the
block storage device of your micro-SD):
DEV=/dev/sdc
# zero out 1MB of device
sudo dd if=/dev/zero of=$DEV count=1 bs=1M oflag=sync status=none && sync
# copy SPL to 1KB offset
sudo dd if=SPL of=$DEV bs=1K seek=1 oflag=sync status=none && sync
# copy U-Boot to 69KB offset
sudo dd if=u-boot.img of=$DEV bs=1K seek=69 oflag=sync status=none && sync
# create a partition table with a single rootfs partition starting at 1MB
printf "1,,L\n" | sudo sfdisk --in-order --no-reread -L -uM $DEV && sync
# format partition
sudo mkfs.ext4 -L root ${DEV}1
# mount the partition
sudo udisks --mount ${DEV}1
# extract filesystem
sudo tar xvf rootfs.tar.gz -C /media/root
# flush and unmount
sync && sudo umount /media/root
The above assumes the default Ventana micro-SD partitioning scheme
- spl : 1KB-69KB (68KB) required by IMX6 BOOT ROM
- uboot : 69KB-709KB (640KB) defined by
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
- env : 709KB-965KB (256KB) defined by
CONFIG_ENV_MMC_SIZE
CONFIG_ENV_MMC_OFFSET_REDUND
- rootfs : 1MB-
This information is taken from:
http://trac.gateworks.com/wiki/ventana/bootloader#microsd
More details about the i.MX6 BOOT ROM can be found in the IMX6 reference manual.
4. Falcon Mode
------------------------------
The Gateworks Ventana board config enables Falcon mode (CONFIG_SPL_OS_BOOT)
which allows the SPL to boot directly to an OS instead of to U-Boot
(u-boot.img) thus acheiving a faster overall boot time. The time savings
depends on your boot medium (ie NAND Flash vs micro-SD) and size/storage
of the OS. The time savings can be anywhere from 2 seconds (256MB NAND Flash
with ~1MB kernel) to 6 seconds or more (2GB NAND Flash with ~6 kernel)
The Gateworks Ventana board supports Falcon mode for the following boot
medium:
- NAND flash
- micro-SD
For all boot mediums, raw mode is used. While support of more complex storage
such as files on top of FAT/EXT filesystem is possible but not practical
as the size of the SPL is fairly limitted (to 64KB based on the smallest
size of available IMX6 iRAM) as well as the fact that this would increase
OS load time which defeats the purpose of Falcon mode in the first place.
The SPL decides to boot either U-Boot (u-boot.img) or the OS (args + kernel)
based on the return value of the spl_start_uboot() function. While often
this can simply be the state of a GPIO based pushbutton or DIP switch, for
Gateworks Ventana, we use an EEPROM register on i2c-0 at 0x50:0x00:
set to '0' will choose to boot to U-Boot and otherwise it will boot to OS.
To use Falcon mode it is required that you first 'prepare' the 'args' data
that is stored on your boot medium along with the kernel (which can be any
OS or bare-metal application). In the case of the Linux kernel the 'args'
is the flatenned device-tree which normally gets altered prior to booting linux
by U-Boot's 'bootm' command. To achieve this for SPL we use the
'spl export fdt' command in U-Boot after loading the kernel and dtb which
will go through the same process of modifying the device-tree for the board
being executed on but not jump to the kernel. This allows you to save the
args data to the location the SPL expects it and then enable Falcon mode.
It is important to realize that there are certain values in the dtb that
are board model specific (IMX6Q vs IMX6DL for example) and board specific
(board serial number, MAC addrs) so you do not want to use the 'args'
data prepared from one board on another board.
4.1. Falcon Mode on NAND flash
------------------------------
To prepare a Gateworks Ventana board that boots from NAND flash for Falcon
mode you must program your flash such that the 'args' and 'kernel' are
located where defined at compile time by the following:
CONFIG_CMD_SPL_NAND_OFS 17MB - offset of 'args'
CONFIG_SYS_NAND_SPL_KERNEL_OFFS 18MB - offset of 'kernel'
The location offsets defined above are defaults chosen by Gateworks and are
flexible if you want to re-define them.
The following steps executed in U-Boot will configure Falcon mode for NAND
using rootfs (ubi), kernel (uImage), and dtb from the network:
# change mtd partitions to the above mapping
Ventana > setenv mtdparts 'mtdparts=nand:14m(spl),2m(uboot),1m(env),1m(args),10m(kernel),-(rootfs)'
# flash rootfs (at 28MB)
Ventana > tftp ${loadaddr} rootfs_${flash_layout}.ubi && \
nand erase.part rootfs && nand write ${loadaddr} rootfs ${filesize}
# load the device-tree
Ventana > tftp ${fdt_addr} ventana/${fdt_file2}
# load the kernel
Ventana > tftp ${loadaddr} ventana/uImage
# flash kernel (at 18MB)
Ventana > nand erase.part kernel && nand write ${loadaddr} kernel ${filesize}
# set kernel args for the console and rootfs (used by spl export)
Ventana > setenv bootargs 'console=ttymxc1,115200 root=ubi0:rootfs ubi.mtd=5 rootfstype=ubifs quiet'
# create args based on env, board, EEPROM, and dtb
Ventana > spl export fdt ${loadaddr} - ${fdt_addr}
# flash args (at 17MB)
Ventana > nand erase.part args && nand write 18000000 args 100000
# set i2c register 0x50:0x00=0 to boot to Linux
Ventana > i2c dev 0 && i2c mw 0x50 0x00.0 0 1
Be sure to adjust 'bootargs' above to your OS needs (this will be different
for various distros such as OpenWrt, Yocto, Android, etc). You can use the
value obtained from 'cat /proc/cmdline' when booted to Linux.
This information is taken from:
http://trac.gateworks.com/wiki/ventana/bootloader/falcon-mode#nand
4.2. Falcon Mode on micro-SD card
---------------------------------
To prepare a Gateworks Ventana board with a primary boot device of micro-SD
you first need to make sure you build U-Boot with CONFIG_ENV_IS_IN_MMC
instead of CONFIG_ENV_IS_IN_NAND.
For micro-SD based Falcon mode you must program your micro-SD such that
the 'args' and 'kernel' are located where defined at compile time
by the following:
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR 0x800 (1MB) - offset of 'args'
CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR 0x1000 (2MB) - offset of 'kernel'
The location offsets defined above are defaults chosen by Gateworks and are
flexible if you want to re-define them.
First you must prepare a micro-SD such that the SPL can be loaded by the
IMX6 BOOT ROM (fixed offset of 1KB), and U-Boot can be loaded by the SPL
(fixed offset of 69KB defined by CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR).
The following shell commands are executed on a Linux host (adjust DEV to the
block storage device of your micro-SD):
DEV=/dev/sdc
# zero out 1MB of device
sudo dd if=/dev/zero of=$DEV count=1 bs=1M oflag=sync status=none && sync
# copy SPL to 1KB offset
sudo dd if=SPL of=$DEV bs=1K seek=1 oflag=sync status=none && sync
# copy U-Boot to 69KB offset
sudo dd if=u-boot.img of=$DEV bs=1K seek=69 oflag=sync status=none && sync
# create a partition table with a single rootfs partition starting at 10MB
printf "10,,L\n" | sudo sfdisk --in-order --no-reread -L -uM $DEV && sync
# format partition
sudo mkfs.ext4 -L root ${DEV}1
# mount the partition
sudo udisks --mount ${DEV}1
# extract filesystem
sudo tar xvf rootfs.tar.gz -C /media/root
# flush and unmount
sync && sudo umount /media/root
Now that your micro-SD partitioning has been adjusted to leave room for the
raw 'args' and 'kernel' data boot the board with the prepared micro-SD, break
out in U-Boot and use the following to enable Falcon mode:
# load device-tree from rootfs
Ventana > ext2load mmc 0:1 ${fdt_addr} boot/${fdt_file2}
# load kernel from rootfs
Ventana > ext2load mmc 0:1 ${loadaddr} boot/uImage
# write kernel at 2MB offset
Ventana > mmc write ${loadaddr} 0x1000 0x4000
# setup kernel bootargs
Ventana > setenv bootargs 'console=ttymxc1,115200 root=/dev/mmcblk0p1 rootfstype=ext4 rootwait rw'
# prepare args
Ventana > spl export fdt ${loadaddr} - ${fdt_addr}
# write args 1MB data (0x800 sectors) to 1MB offset (0x800 sectors)
Ventana > mmc write 18000000 0x800 0x800
# set i2c register 0x50:0x00=0 to boot to Linux
Ventana > i2c dev 0 && i2c mw 0x50 0x00.0 0 1
Be sure to adjust 'bootargs' above to your OS needs (this will be different
for various distros such as OpenWrt, Yocto, Android, etc). You can use the
value obtained from 'cat /proc/cmdline' when booted to Linux.
This information is taken from:
http://trac.gateworks.com/wiki/ventana/bootloader/falcon-mode#microsd

View File

@@ -0,0 +1,925 @@
/*
* Copyright (C) 2013 Gateworks Corporation
*
* Author: Tim Harvey <tharvey@gateworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/arch/mx6-pins.h>
#include <asm/arch/sys_proto.h>
#include <asm/gpio.h>
#include <asm/imx-common/mxc_i2c.h>
#include <hwconfig.h>
#include <power/pmic.h>
#include <power/ltc3676_pmic.h>
#include <power/pfuze100_pmic.h>
#include "common.h"
/* UART1: Function varies per baseboard */
static iomux_v3_cfg_t const uart1_pads[] = {
IOMUX_PADS(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
IOMUX_PADS(PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
};
/* UART2: Serial Console */
static iomux_v3_cfg_t const uart2_pads[] = {
IOMUX_PADS(PAD_SD4_DAT7__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
IOMUX_PADS(PAD_SD4_DAT4__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
};
void setup_iomux_uart(void)
{
SETUP_IOMUX_PADS(uart1_pads);
SETUP_IOMUX_PADS(uart2_pads);
}
/* I2C1: GSC */
static struct i2c_pads_info mx6q_i2c_pad_info0 = {
.scl = {
.i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6Q_PAD_EIM_D21__GPIO3_IO21 | PC,
.gp = IMX_GPIO_NR(3, 21)
},
.sda = {
.i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6Q_PAD_EIM_D28__GPIO3_IO28 | PC,
.gp = IMX_GPIO_NR(3, 28)
}
};
static struct i2c_pads_info mx6dl_i2c_pad_info0 = {
.scl = {
.i2c_mode = MX6DL_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6DL_PAD_EIM_D21__GPIO3_IO21 | PC,
.gp = IMX_GPIO_NR(3, 21)
},
.sda = {
.i2c_mode = MX6DL_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6DL_PAD_EIM_D28__GPIO3_IO28 | PC,
.gp = IMX_GPIO_NR(3, 28)
}
};
/* I2C2: PMIC/PCIe Switch/PCIe Clock/Mezz */
static struct i2c_pads_info mx6q_i2c_pad_info1 = {
.scl = {
.i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6Q_PAD_KEY_COL3__GPIO4_IO12 | PC,
.gp = IMX_GPIO_NR(4, 12)
},
.sda = {
.i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO4_IO13 | PC,
.gp = IMX_GPIO_NR(4, 13)
}
};
static struct i2c_pads_info mx6dl_i2c_pad_info1 = {
.scl = {
.i2c_mode = MX6DL_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6DL_PAD_KEY_COL3__GPIO4_IO12 | PC,
.gp = IMX_GPIO_NR(4, 12)
},
.sda = {
.i2c_mode = MX6DL_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6DL_PAD_KEY_ROW3__GPIO4_IO13 | PC,
.gp = IMX_GPIO_NR(4, 13)
}
};
/* I2C3: Misc/Expansion */
static struct i2c_pads_info mx6q_i2c_pad_info2 = {
.scl = {
.i2c_mode = MX6Q_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6Q_PAD_GPIO_3__GPIO1_IO03 | PC,
.gp = IMX_GPIO_NR(1, 3)
},
.sda = {
.i2c_mode = MX6Q_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6Q_PAD_GPIO_6__GPIO1_IO06 | PC,
.gp = IMX_GPIO_NR(1, 6)
}
};
static struct i2c_pads_info mx6dl_i2c_pad_info2 = {
.scl = {
.i2c_mode = MX6DL_PAD_GPIO_3__I2C3_SCL | PC,
.gpio_mode = MX6DL_PAD_GPIO_3__GPIO1_IO03 | PC,
.gp = IMX_GPIO_NR(1, 3)
},
.sda = {
.i2c_mode = MX6DL_PAD_GPIO_6__I2C3_SDA | PC,
.gpio_mode = MX6DL_PAD_GPIO_6__GPIO1_IO06 | PC,
.gp = IMX_GPIO_NR(1, 6)
}
};
void setup_ventana_i2c(void)
{
if (is_cpu_type(MXC_CPU_MX6Q)) {
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info0);
setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info1);
setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6q_i2c_pad_info2);
} else {
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info0);
setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info1);
setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &mx6dl_i2c_pad_info2);
}
}
/*
* Baseboard specific GPIO
*/
/* common to add baseboards */
static iomux_v3_cfg_t const gw_gpio_pads[] = {
/* RS232_EN# */
IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | DIO_PAD_CFG),
/* SD3_VSELECT */
IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG),
};
/* prototype */
static iomux_v3_cfg_t const gwproto_gpio_pads[] = {
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* LOCLED# */
IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG),
/* RS485_EN */
IOMUX_PADS(PAD_SD3_DAT4__GPIO7_IO01 | DIO_PAD_CFG),
/* IOEXP_PWREN# */
IOMUX_PADS(PAD_EIM_A19__GPIO2_IO19 | DIO_PAD_CFG),
/* IOEXP_IRQ# */
IOMUX_PADS(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(IRQ_PAD_CTRL)),
/* VID_EN */
IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG),
/* DIOI2C_DIS# */
IOMUX_PADS(PAD_GPIO_19__GPIO4_IO05 | DIO_PAD_CFG),
/* PCICK_SSON */
IOMUX_PADS(PAD_SD1_CLK__GPIO1_IO20 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_ENET_TXD1__GPIO1_IO29 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw51xx_gpio_pads[] = {
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* IOEXP_PWREN# */
IOMUX_PADS(PAD_EIM_A19__GPIO2_IO19 | DIO_PAD_CFG),
/* IOEXP_IRQ# */
IOMUX_PADS(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(IRQ_PAD_CTRL)),
/* GPS_SHDN */
IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG),
/* VID_PWR */
IOMUX_PADS(PAD_CSI0_DATA_EN__GPIO5_IO20 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_GPIO_0__GPIO1_IO00 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw52xx_gpio_pads[] = {
/* MSATA_EN */
IOMUX_PADS(PAD_SD4_DAT0__GPIO2_IO08 | DIO_PAD_CFG),
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* IOEXP_PWREN# */
IOMUX_PADS(PAD_EIM_A19__GPIO2_IO19 | DIO_PAD_CFG),
/* IOEXP_IRQ# */
IOMUX_PADS(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(IRQ_PAD_CTRL)),
/* CAN_STBY */
IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09 | DIO_PAD_CFG),
/* MX6_LOCLED# */
IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG),
/* GPS_SHDN */
IOMUX_PADS(PAD_ENET_RXD0__GPIO1_IO27 | DIO_PAD_CFG),
/* USBOTG_SEL */
IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG),
/* VID_PWR */
IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_ENET_TXD1__GPIO1_IO29 | DIO_PAD_CFG),
/* PCI_RST# (GW522x) */
IOMUX_PADS(PAD_EIM_D23__GPIO3_IO23 | DIO_PAD_CFG),
/* RS485_EN */
IOMUX_PADS(PAD_SD3_DAT4__GPIO7_IO01 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw53xx_gpio_pads[] = {
/* MSATA_EN */
IOMUX_PADS(PAD_SD4_DAT0__GPIO2_IO08 | DIO_PAD_CFG),
/* CAN_STBY */
IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG),
/* USB_HUBRST# */
IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09 | DIO_PAD_CFG),
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* MX6_LOCLED# */
IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG),
/* IOEXP_PWREN# */
IOMUX_PADS(PAD_EIM_A19__GPIO2_IO19 | DIO_PAD_CFG),
/* IOEXP_IRQ# */
IOMUX_PADS(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(IRQ_PAD_CTRL)),
/* DIOI2C_DIS# */
IOMUX_PADS(PAD_GPIO_19__GPIO4_IO05 | DIO_PAD_CFG),
/* GPS_SHDN */
IOMUX_PADS(PAD_ENET_RXD0__GPIO1_IO27 | DIO_PAD_CFG),
/* VID_EN */
IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_ENET_TXD1__GPIO1_IO29 | DIO_PAD_CFG),
/* RS485_EN */
IOMUX_PADS(PAD_SD3_DAT4__GPIO7_IO01 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw54xx_gpio_pads[] = {
/* MSATA_EN */
IOMUX_PADS(PAD_SD4_DAT0__GPIO2_IO08 | DIO_PAD_CFG),
/* CAN_STBY */
IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG),
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* MX6_LOCLED# */
IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG),
/* USB_HUBRST# */
IOMUX_PADS(PAD_SD1_DAT0__GPIO1_IO16 | DIO_PAD_CFG),
/* MIPI_DIO */
IOMUX_PADS(PAD_SD1_DAT3__GPIO1_IO21 | DIO_PAD_CFG),
/* RS485_EN */
IOMUX_PADS(PAD_EIM_D24__GPIO3_IO24 | DIO_PAD_CFG),
/* IOEXP_PWREN# */
IOMUX_PADS(PAD_EIM_A19__GPIO2_IO19 | DIO_PAD_CFG),
/* IOEXP_IRQ# */
IOMUX_PADS(PAD_EIM_A20__GPIO2_IO18 | MUX_PAD_CTRL(IRQ_PAD_CTRL)),
/* DIOI2C_DIS# */
IOMUX_PADS(PAD_GPIO_19__GPIO4_IO05 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_ENET_TXD1__GPIO1_IO29 | DIO_PAD_CFG),
/* VID_EN */
IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG),
/* RS485_EN */
IOMUX_PADS(PAD_SD3_DAT4__GPIO7_IO01 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_DISP0_DAT23__GPIO5_IO17 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw551x_gpio_pads[] = {
/* CAN_STBY */
IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09 | DIO_PAD_CFG),
/* PANLED# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_GPIO_0__GPIO1_IO00 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw552x_gpio_pads[] = {
/* MSATA_EN */
IOMUX_PADS(PAD_SD4_DAT0__GPIO2_IO08 | DIO_PAD_CFG),
/* USBOTG_SEL */
IOMUX_PADS(PAD_GPIO_7__GPIO1_IO07 | DIO_PAD_CFG),
/* USB_HUBRST# */
IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09 | DIO_PAD_CFG),
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG),
/* MX6_LOCLED# */
IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_ENET_TXD1__GPIO1_IO29 | DIO_PAD_CFG),
/* MX6_DIO[4:9] */
IOMUX_PADS(PAD_CSI0_PIXCLK__GPIO5_IO18 | DIO_PAD_CFG),
IOMUX_PADS(PAD_CSI0_DATA_EN__GPIO5_IO20 | DIO_PAD_CFG),
IOMUX_PADS(PAD_CSI0_VSYNC__GPIO5_IO21 | DIO_PAD_CFG),
IOMUX_PADS(PAD_CSI0_DAT4__GPIO5_IO22 | DIO_PAD_CFG),
IOMUX_PADS(PAD_CSI0_DAT5__GPIO5_IO23 | DIO_PAD_CFG),
IOMUX_PADS(PAD_CSI0_DAT7__GPIO5_IO25 | DIO_PAD_CFG),
/* PCIEGBE1_OFF# */
IOMUX_PADS(PAD_GPIO_1__GPIO1_IO01 | DIO_PAD_CFG),
/* PCIEGBE2_OFF# */
IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG),
};
static iomux_v3_cfg_t const gw553x_gpio_pads[] = {
/* PANLEDG# */
IOMUX_PADS(PAD_KEY_COL2__GPIO4_IO10 | DIO_PAD_CFG),
/* PANLEDR# */
IOMUX_PADS(PAD_KEY_ROW2__GPIO4_IO11 | DIO_PAD_CFG),
/* VID_PWR */
IOMUX_PADS(PAD_CSI0_DATA_EN__GPIO5_IO20 | DIO_PAD_CFG),
/* PCI_RST# */
IOMUX_PADS(PAD_GPIO_0__GPIO1_IO00 | DIO_PAD_CFG),
/* PCIESKT_WDIS# */
IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG),
};
/*
* Board Specific GPIO
*/
struct ventana gpio_cfg[GW_UNKNOWN] = {
/* GW5400proto */
{
.gpio_pads = gw54xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09) },
IMX_GPIO_NR(1, 9),
{ IOMUX_PADS(PAD_GPIO_9__PWM1_OUT) },
1
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD4_DAT1__GPIO2_IO09) },
IMX_GPIO_NR(2, 9),
{ IOMUX_PADS(PAD_SD4_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX_PADS(PAD_SD4_DAT2__GPIO2_IO10) },
IMX_GPIO_NR(2, 10),
{ IOMUX_PADS(PAD_SD4_DAT2__PWM4_OUT) },
4
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 6),
IMX_GPIO_NR(4, 10),
IMX_GPIO_NR(4, 15),
},
.pcie_rst = IMX_GPIO_NR(1, 29),
.mezz_pwren = IMX_GPIO_NR(4, 7),
.mezz_irq = IMX_GPIO_NR(4, 9),
.rs485en = IMX_GPIO_NR(3, 24),
.dioi2c_en = IMX_GPIO_NR(4, 5),
.pcie_sson = IMX_GPIO_NR(1, 20),
},
/* GW51xx */
{
.gpio_pads = gw51xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw51xx_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX_PADS(PAD_SD1_CMD__GPIO1_IO18) },
IMX_GPIO_NR(1, 18),
{ IOMUX_PADS(PAD_SD1_CMD__PWM4_OUT) },
4
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 6),
IMX_GPIO_NR(4, 10),
},
.pcie_rst = IMX_GPIO_NR(1, 0),
.mezz_pwren = IMX_GPIO_NR(2, 19),
.mezz_irq = IMX_GPIO_NR(2, 18),
.gps_shdn = IMX_GPIO_NR(1, 2),
.vidin_en = IMX_GPIO_NR(5, 20),
.wdis = IMX_GPIO_NR(7, 12),
},
/* GW52xx */
{
.gpio_pads = gw52xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw52xx_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX_PADS(PAD_SD1_CLK__GPIO1_IO20) },
IMX_GPIO_NR(1, 20),
{ 0, 0 },
0
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 6),
IMX_GPIO_NR(4, 7),
IMX_GPIO_NR(4, 15),
},
.pcie_rst = IMX_GPIO_NR(1, 29),
.mezz_pwren = IMX_GPIO_NR(2, 19),
.mezz_irq = IMX_GPIO_NR(2, 18),
.gps_shdn = IMX_GPIO_NR(1, 27),
.vidin_en = IMX_GPIO_NR(3, 31),
.usb_sel = IMX_GPIO_NR(1, 2),
.wdis = IMX_GPIO_NR(7, 12),
.msata_en = GP_MSATA_SEL,
},
/* GW53xx */
{
.gpio_pads = gw53xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw53xx_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{IOMUX_PADS(PAD_SD1_CLK__GPIO1_IO20) },
IMX_GPIO_NR(1, 20),
{ 0, 0 },
0
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 6),
IMX_GPIO_NR(4, 7),
IMX_GPIO_NR(4, 15),
},
.pcie_rst = IMX_GPIO_NR(1, 29),
.mezz_pwren = IMX_GPIO_NR(2, 19),
.mezz_irq = IMX_GPIO_NR(2, 18),
.gps_shdn = IMX_GPIO_NR(1, 27),
.vidin_en = IMX_GPIO_NR(3, 31),
.wdis = IMX_GPIO_NR(7, 12),
.msata_en = GP_MSATA_SEL,
},
/* GW54xx */
{
.gpio_pads = gw54xx_gpio_pads,
.num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09) },
IMX_GPIO_NR(1, 9),
{ IOMUX_PADS(PAD_GPIO_9__PWM1_OUT) },
1
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD4_DAT1__GPIO2_IO09) },
IMX_GPIO_NR(2, 9),
{ IOMUX_PADS(PAD_SD4_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX_PADS(PAD_SD4_DAT2__GPIO2_IO10) },
IMX_GPIO_NR(2, 10),
{ IOMUX_PADS(PAD_SD4_DAT2__PWM4_OUT) },
4
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 6),
IMX_GPIO_NR(4, 7),
IMX_GPIO_NR(4, 15),
},
.pcie_rst = IMX_GPIO_NR(1, 29),
.mezz_pwren = IMX_GPIO_NR(2, 19),
.mezz_irq = IMX_GPIO_NR(2, 18),
.rs485en = IMX_GPIO_NR(7, 1),
.vidin_en = IMX_GPIO_NR(3, 31),
.dioi2c_en = IMX_GPIO_NR(4, 5),
.pcie_sson = IMX_GPIO_NR(1, 20),
.wdis = IMX_GPIO_NR(5, 17),
.msata_en = GP_MSATA_SEL,
},
/* GW551x */
{
.gpio_pads = gw551x_gpio_pads,
.num_pads = ARRAY_SIZE(gw551x_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) },
3
},
},
.num_gpios = 2,
.leds = {
IMX_GPIO_NR(4, 7),
},
.pcie_rst = IMX_GPIO_NR(1, 0),
.wdis = IMX_GPIO_NR(7, 12),
},
/* GW552x */
{
.gpio_pads = gw552x_gpio_pads,
.num_pads = ARRAY_SIZE(gw552x_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{IOMUX_PADS(PAD_SD1_CLK__GPIO1_IO20) },
IMX_GPIO_NR(1, 20),
{ 0, 0 },
0
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 6),
IMX_GPIO_NR(4, 7),
IMX_GPIO_NR(4, 15),
},
.pcie_rst = IMX_GPIO_NR(1, 29),
.usb_sel = IMX_GPIO_NR(1, 7),
.wdis = IMX_GPIO_NR(7, 12),
.msata_en = GP_MSATA_SEL,
},
/* GW553x */
{
.gpio_pads = gw553x_gpio_pads,
.num_pads = ARRAY_SIZE(gw553x_gpio_pads)/2,
.dio_cfg = {
{
{ IOMUX_PADS(PAD_SD1_DAT0__GPIO1_IO16) },
IMX_GPIO_NR(1, 16),
{ 0, 0 },
0
},
{
{ IOMUX_PADS(PAD_SD1_DAT2__GPIO1_IO19) },
IMX_GPIO_NR(1, 19),
{ IOMUX_PADS(PAD_SD1_DAT2__PWM2_OUT) },
2
},
{
{ IOMUX_PADS(PAD_SD1_DAT1__GPIO1_IO17) },
IMX_GPIO_NR(1, 17),
{ IOMUX_PADS(PAD_SD1_DAT1__PWM3_OUT) },
3
},
{
{ IOMUX_PADS(PAD_SD1_CMD__GPIO1_IO18) },
IMX_GPIO_NR(1, 18),
{ IOMUX_PADS(PAD_SD1_CMD__PWM4_OUT) },
4
},
},
.num_gpios = 4,
.leds = {
IMX_GPIO_NR(4, 10),
IMX_GPIO_NR(4, 11),
},
.pcie_rst = IMX_GPIO_NR(1, 0),
.vidin_en = IMX_GPIO_NR(5, 20),
.wdis = IMX_GPIO_NR(7, 12),
},
};
void setup_iomux_gpio(int board, struct ventana_board_info *info)
{
int i;
/* iomux common to all Ventana boards */
SETUP_IOMUX_PADS(gw_gpio_pads);
/* OTG power off */
gpio_request(GP_USB_OTG_PWR, "usbotg_pwr");
gpio_direction_output(GP_USB_OTG_PWR, 0);
/* RS232_EN# */
gpio_request(GP_RS232_EN, "rs232_en");
gpio_direction_output(GP_RS232_EN, 0);
if (board >= GW_UNKNOWN)
return;
/* board specific iomux */
imx_iomux_v3_setup_multiple_pads(gpio_cfg[board].gpio_pads,
gpio_cfg[board].num_pads);
/* GW522x Uses GPIO3_IO23 for PCIE_RST# */
if (board == GW52xx && info->model[4] == '2')
gpio_cfg[board].pcie_rst = IMX_GPIO_NR(3, 23);
/* assert PCI_RST# */
gpio_request(gpio_cfg[board].pcie_rst, "pci_rst#");
gpio_direction_output(gpio_cfg[board].pcie_rst, 0);
/* turn off (active-high) user LED's */
for (i = 0; i < ARRAY_SIZE(gpio_cfg[board].leds); i++) {
char name[16];
if (gpio_cfg[board].leds[i]) {
sprintf(name, "led_user%d", i);
gpio_request(gpio_cfg[board].leds[i], name);
gpio_direction_output(gpio_cfg[board].leds[i], 1);
}
}
/* MSATA Enable - default to PCI */
if (gpio_cfg[board].msata_en) {
gpio_request(gpio_cfg[board].msata_en, "msata_en");
gpio_direction_output(gpio_cfg[board].msata_en, 0);
}
/* Expansion Mezzanine IO */
if (gpio_cfg[board].mezz_pwren) {
gpio_request(gpio_cfg[board].mezz_pwren, "mezz_pwr");
gpio_direction_output(gpio_cfg[board].mezz_pwren, 0);
}
if (gpio_cfg[board].mezz_irq) {
gpio_request(gpio_cfg[board].mezz_irq, "mezz_irq#");
gpio_direction_input(gpio_cfg[board].mezz_irq);
}
/* RS485 Transmit Enable */
if (gpio_cfg[board].rs485en) {
gpio_request(gpio_cfg[board].rs485en, "rs485_en");
gpio_direction_output(gpio_cfg[board].rs485en, 0);
}
/* GPS_SHDN */
if (gpio_cfg[board].gps_shdn) {
gpio_request(gpio_cfg[board].gps_shdn, "gps_shdn");
gpio_direction_output(gpio_cfg[board].gps_shdn, 1);
}
/* Analog video codec power enable */
if (gpio_cfg[board].vidin_en) {
gpio_request(gpio_cfg[board].vidin_en, "anavidin_en");
gpio_direction_output(gpio_cfg[board].vidin_en, 1);
}
/* DIOI2C_DIS# */
if (gpio_cfg[board].dioi2c_en) {
gpio_request(gpio_cfg[board].dioi2c_en, "dioi2c_dis#");
gpio_direction_output(gpio_cfg[board].dioi2c_en, 0);
}
/* PCICK_SSON: disable spread-spectrum clock */
if (gpio_cfg[board].pcie_sson) {
gpio_request(gpio_cfg[board].pcie_sson, "pci_sson");
gpio_direction_output(gpio_cfg[board].pcie_sson, 0);
}
/* USBOTG mux routing */
if (gpio_cfg[board].usb_sel) {
gpio_request(gpio_cfg[board].usb_sel, "usb_pcisel");
gpio_direction_output(gpio_cfg[board].usb_sel, 0);
}
/* PCISKT_WDIS# (Wireless disable GPIO to miniPCIe sockets) */
if (gpio_cfg[board].wdis) {
gpio_request(gpio_cfg[board].wdis, "wlan_dis");
gpio_direction_output(gpio_cfg[board].wdis, 1);
}
/* sense vselect pin to see if we support uhs-i */
gpio_request(GP_SD3_VSELECT, "sd3_vselect");
gpio_direction_input(GP_SD3_VSELECT);
gpio_cfg[board].usd_vsel = !gpio_get_value(GP_SD3_VSELECT);
}
/* setup GPIO pinmux and default configuration per baseboard and env */
void setup_board_gpio(int board, struct ventana_board_info *info)
{
const char *s;
char arg[10];
size_t len;
int i;
int quiet = simple_strtol(getenv("quiet"), NULL, 10);
if (board >= GW_UNKNOWN)
return;
/* RS232_EN# */
gpio_direction_output(GP_RS232_EN, (hwconfig("rs232")) ? 0 : 1);
/* MSATA Enable */
if (gpio_cfg[board].msata_en && is_cpu_type(MXC_CPU_MX6Q)) {
gpio_direction_output(GP_MSATA_SEL,
(hwconfig("msata")) ? 1 : 0);
}
/* USBOTG Select (PCISKT or FrontPanel) */
if (gpio_cfg[board].usb_sel) {
gpio_direction_output(gpio_cfg[board].usb_sel,
(hwconfig("usb_pcisel")) ? 1 : 0);
}
/*
* Configure DIO pinmux/padctl registers
* see IMX6DQRM/IMX6SDLRM IOMUXC_SW_PAD_CTL_PAD_* register definitions
*/
for (i = 0; i < gpio_cfg[board].num_gpios; i++) {
struct dio_cfg *cfg = &gpio_cfg[board].dio_cfg[i];
iomux_v3_cfg_t ctrl = DIO_PAD_CFG;
unsigned cputype = is_cpu_type(MXC_CPU_MX6Q) ? 0 : 1;
if (!cfg->gpio_padmux[0] && !cfg->gpio_padmux[1])
continue;
sprintf(arg, "dio%d", i);
if (!hwconfig(arg))
continue;
s = hwconfig_subarg(arg, "padctrl", &len);
if (s) {
ctrl = MUX_PAD_CTRL(simple_strtoul(s, NULL, 16)
& 0x1ffff) | MUX_MODE_SION;
}
if (hwconfig_subarg_cmp(arg, "mode", "gpio")) {
if (!quiet) {
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[cputype] |
ctrl);
gpio_requestf(cfg->gpio_param, "dio%d", i);
gpio_direction_input(cfg->gpio_param);
} else if (hwconfig_subarg_cmp(arg, "mode", "pwm") &&
cfg->pwm_padmux) {
if (!cfg->pwm_param) {
printf("DIO%d: Error: pwm config invalid\n",
i);
continue;
}
if (!quiet)
printf("DIO%d: pwm%d\n", i, cfg->pwm_param);
imx_iomux_v3_setup_pad(cfg->pwm_padmux[cputype] |
MUX_PAD_CTRL(ctrl));
}
}
if (!quiet) {
if (gpio_cfg[board].msata_en && is_cpu_type(MXC_CPU_MX6Q)) {
printf("MSATA: %s\n", (hwconfig("msata") ?
"enabled" : "disabled"));
}
printf("RS232: %s\n", (hwconfig("rs232")) ?
"enabled" : "disabled");
}
}
/* setup board specific PMIC */
void setup_pmic(void)
{
struct pmic *p;
u32 reg;
i2c_set_bus_num(CONFIG_I2C_PMIC);
/* configure PFUZE100 PMIC */
if (!i2c_probe(CONFIG_POWER_PFUZE100_I2C_ADDR)) {
debug("probed PFUZE100@0x%x\n", CONFIG_POWER_PFUZE100_I2C_ADDR);
power_pfuze100_init(CONFIG_I2C_PMIC);
p = pmic_get("PFUZE100");
if (p && !pmic_probe(p)) {
pmic_reg_read(p, PFUZE100_DEVICEID, &reg);
printf("PMIC: PFUZE100 ID=0x%02x\n", reg);
/* Set VGEN1 to 1.5V and enable */
pmic_reg_read(p, PFUZE100_VGEN1VOL, &reg);
reg &= ~(LDO_VOL_MASK);
reg |= (LDOA_1_50V | LDO_EN);
pmic_reg_write(p, PFUZE100_VGEN1VOL, reg);
/* Set SWBST to 5.0V and enable */
pmic_reg_read(p, PFUZE100_SWBSTCON1, &reg);
reg &= ~(SWBST_MODE_MASK | SWBST_VOL_MASK);
reg |= (SWBST_5_00V | (SWBST_MODE_AUTO << SWBST_MODE_SHIFT));
pmic_reg_write(p, PFUZE100_SWBSTCON1, reg);
}
}
/* configure LTC3676 PMIC */
else if (!i2c_probe(CONFIG_POWER_LTC3676_I2C_ADDR)) {
debug("probed LTC3676@0x%x\n", CONFIG_POWER_LTC3676_I2C_ADDR);
power_ltc3676_init(CONFIG_I2C_PMIC);
p = pmic_get("LTC3676_PMIC");
if (p && !pmic_probe(p)) {
puts("PMIC: LTC3676\n");
/*
* set board-specific scalar for max CPU frequency
* per CPU based on the LDO enabled Operating Ranges
* defined in the respective IMX6DQ and IMX6SDL
* datasheets. The voltage resulting from the R1/R2
* feedback inputs on Ventana is 1308mV. Note that this
* is a bit shy of the Vmin of 1350mV in the datasheet
* for LDO enabled mode but is as high as we can go.
*
* We will rely on an OS kernel driver to properly
* regulate these per CPU operating point and use LDO
* bypass mode when using the higher frequency
* operating points to compensate as LDO bypass mode
* allows the rails be 125mV lower.
*/
/* mask PGOOD during SW1 transition */
pmic_reg_write(p, LTC3676_DVB1B,
0x1f | LTC3676_PGOOD_MASK);
/* set SW1 (VDD_SOC) */
pmic_reg_write(p, LTC3676_DVB1A, 0x1f);
/* mask PGOOD during SW3 transition */
pmic_reg_write(p, LTC3676_DVB3B,
0x1f | LTC3676_PGOOD_MASK);
/* set SW3 (VDD_ARM) */
pmic_reg_write(p, LTC3676_DVB3A, 0x1f);
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2013 Gateworks Corporation
*
* Author: Tim Harvey <tharvey@gateworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _GWVENTANA_COMMON_H_
#define _GWVENTANA_COMMON_H_
#include "ventana_eeprom.h"
/* GPIO's common to all baseboards */
#define GP_PHY_RST IMX_GPIO_NR(1, 30)
#define GP_USB_OTG_PWR IMX_GPIO_NR(3, 22)
#define GP_SD3_CD IMX_GPIO_NR(7, 0)
#define GP_RS232_EN IMX_GPIO_NR(2, 11)
#define GP_MSATA_SEL IMX_GPIO_NR(2, 8)
#define GP_SD3_VSELECT IMX_GPIO_NR(6, 14)
#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 IRQ_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 DIO_PAD_CFG (MUX_PAD_CTRL(IRQ_PAD_CTRL) | MUX_MODE_SION)
#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
/*
* each baseboard has 4 user configurable Digital IO lines which can
* be pinmuxed as a GPIO or in some cases a PWM
*/
struct dio_cfg {
iomux_v3_cfg_t gpio_padmux[2];
unsigned gpio_param;
iomux_v3_cfg_t pwm_padmux[2];
unsigned pwm_param;
};
struct ventana {
/* pinmux */
iomux_v3_cfg_t const *gpio_pads;
int num_pads;
/* DIO pinmux/val */
struct dio_cfg dio_cfg[4];
int num_gpios;
/* various gpios (0 if non-existent) */
int leds[3];
int pcie_rst;
int mezz_pwren;
int mezz_irq;
int rs485en;
int gps_shdn;
int vidin_en;
int dioi2c_en;
int pcie_sson;
int usb_sel;
int wdis;
int msata_en;
bool usd_vsel;
};
extern struct ventana gpio_cfg[GW_UNKNOWN];
/* configure i2c iomux */
void setup_ventana_i2c(void);
/* configure uart iomux */
void setup_iomux_uart(void);
/* conifgure PMIC */
void setup_pmic(void);
/* configure gpio iomux/defaults */
void setup_iomux_gpio(int board, struct ventana_board_info *);
/* late setup of GPIO (configuration per baseboard and env) */
void setup_board_gpio(int board, struct ventana_board_info *);
#endif /* #ifndef _GWVENTANA_COMMON_H_ */

View File

@@ -0,0 +1,232 @@
/*
* Copyright (C) 2014 Gateworks Corporation
* Author: Tim Harvey <tharvey@gateworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <errno.h>
#include <i2c.h>
#include <malloc.h>
#include <asm/bitops.h>
#include "gsc.h"
#include "ventana_eeprom.h"
/* read ventana EEPROM, check for validity, and return baseboard type */
int
read_eeprom(int bus, struct ventana_board_info *info)
{
int i;
int chksum;
char baseboard;
int type;
unsigned char *buf = (unsigned char *)info;
memset(info, 0, sizeof(*info));
/*
* On a board with a missing/depleted backup battery for GSC, the
* board may be ready to probe the GSC before its firmware is
* running. We will wait here indefinately for the GSC/EEPROM.
*/
while (1) {
if (0 == i2c_set_bus_num(bus) &&
0 == i2c_probe(GSC_EEPROM_ADDR))
break;
mdelay(1);
}
/* read eeprom config section */
if (gsc_i2c_read(GSC_EEPROM_ADDR, 0x00, 1, buf, sizeof(*info))) {
puts("EEPROM: Failed to read EEPROM\n");
return GW_UNKNOWN;
}
/* sanity checks */
if (info->model[0] != 'G' || info->model[1] != 'W') {
puts("EEPROM: Invalid Model in EEPROM\n");
return GW_UNKNOWN;
}
/* validate checksum */
for (chksum = 0, i = 0; i < sizeof(*info)-2; i++)
chksum += buf[i];
if ((info->chksum[0] != chksum>>8) ||
(info->chksum[1] != (chksum&0xff))) {
puts("EEPROM: Failed EEPROM checksum\n");
return GW_UNKNOWN;
}
/* original GW5400-A prototype */
baseboard = info->model[3];
if (strncasecmp((const char *)info->model, "GW5400-A", 8) == 0)
baseboard = '0';
switch (baseboard) {
case '0': /* original GW5400-A prototype */
type = GW54proto;
break;
case '1':
type = GW51xx;
break;
case '2':
type = GW52xx;
break;
case '3':
type = GW53xx;
break;
case '4':
type = GW54xx;
break;
case '5':
if (info->model[4] == '1') {
type = GW551x;
break;
} else if (info->model[4] == '2') {
type = GW552x;
break;
} else if (info->model[4] == '3') {
type = GW553x;
break;
}
/* fall through */
default:
printf("EEPROM: Unknown model in EEPROM: %s\n", info->model);
type = GW_UNKNOWN;
break;
}
return type;
}
/* list of config bits that the bootloader will remove from dtb if not set */
struct ventana_eeprom_config econfig[] = {
{ "eth0", "ethernet0", EECONFIG_ETH0 },
{ "usb0", NULL, EECONFIG_USB0 },
{ "usb1", NULL, EECONFIG_USB1 },
{ "mmc0", NULL, EECONFIG_SD0 },
{ "mmc1", NULL, EECONFIG_SD1 },
{ "mmc2", NULL, EECONFIG_SD2 },
{ "mmc3", NULL, EECONFIG_SD3 },
{ /* Sentinel */ }
};
#ifdef CONFIG_CMD_EECONFIG
static struct ventana_eeprom_config *get_config(const char *name)
{
struct ventana_eeprom_config *cfg = econfig;
while (cfg->name) {
if (0 == strcmp(name, cfg->name))
return cfg;
cfg++;
}
return NULL;
}
static u8 econfig_bytes[sizeof(ventana_info.config)];
static int econfig_init = -1;
int do_econfig(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct ventana_eeprom_config *cfg;
struct ventana_board_info *info = &ventana_info;
int i;
if (argc < 2)
return CMD_RET_USAGE;
/* initialize */
if (econfig_init != 1) {
memcpy(econfig_bytes, info->config, sizeof(econfig_bytes));
econfig_init = 1;
}
/* list configs */
if ((strncmp(argv[1], "list", 4) == 0)) {
cfg = econfig;
while (cfg->name) {
printf("%s: %d\n", cfg->name,
test_bit(cfg->bit, econfig_bytes) ? 1 : 0);
cfg++;
}
}
/* save */
else if ((strncmp(argv[1], "save", 4) == 0)) {
unsigned char *buf = (unsigned char *)info;
int chksum;
/* calculate new checksum */
memcpy(info->config, econfig_bytes, sizeof(econfig_bytes));
for (chksum = 0, i = 0; i < sizeof(*info)-2; i++)
chksum += buf[i];
debug("old chksum:0x%04x\n",
(info->chksum[0] << 8) | info->chksum[1]);
debug("new chksum:0x%04x\n", chksum);
info->chksum[0] = chksum >> 8;
info->chksum[1] = chksum & 0xff;
/* write new config data */
if (gsc_i2c_write(GSC_EEPROM_ADDR, info->config - (u8 *)info,
1, econfig_bytes, sizeof(econfig_bytes))) {
printf("EEPROM: Failed updating config\n");
return CMD_RET_FAILURE;
}
/* write new config data */
if (gsc_i2c_write(GSC_EEPROM_ADDR, info->chksum - (u8 *)info,
1, info->chksum, 2)) {
printf("EEPROM: Failed updating checksum\n");
return CMD_RET_FAILURE;
}
printf("Config saved to EEPROM\n");
}
/* get config */
else if (argc == 2) {
cfg = get_config(argv[1]);
if (cfg) {
printf("%s: %d\n", cfg->name,
test_bit(cfg->bit, econfig_bytes) ? 1 : 0);
} else {
printf("invalid config: %s\n", argv[1]);
return CMD_RET_FAILURE;
}
}
/* set config */
else if (argc == 3) {
cfg = get_config(argv[1]);
if (cfg) {
if (simple_strtol(argv[2], NULL, 10)) {
test_and_set_bit(cfg->bit, econfig_bytes);
printf("Enabled %s\n", cfg->name);
} else {
test_and_clear_bit(cfg->bit, econfig_bytes);
printf("Disabled %s\n", cfg->name);
}
} else {
printf("invalid config: %s\n", argv[1]);
return CMD_RET_FAILURE;
}
}
else
return CMD_RET_USAGE;
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
econfig, 3, 0, do_econfig,
"EEPROM configuration",
"list - list config\n"
"save - save config to EEPROM\n"
"<name> - get config 'name'\n"
"<name> [0|1] - set config 'name' to value\n"
);
#endif /* CONFIG_CMD_EECONFIG */

View File

@@ -0,0 +1,271 @@
/*
* Copyright (C) 2013 Gateworks Corporation
*
* Author: Tim Harvey <tharvey@gateworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/errno.h>
#include <common.h>
#include <i2c.h>
#include <linux/ctype.h>
#include "ventana_eeprom.h"
#include "gsc.h"
/*
* The Gateworks System Controller will fail to ACK a master transaction if
* it is busy, which can occur during its 1HZ timer tick while reading ADC's.
* When this does occur, it will never be busy long enough to fail more than
* 2 back-to-back transfers. Thus we wrap i2c_read and i2c_write with
* 3 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;
debug("%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;
debug("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
n, ret);
if (ret != -ENODEV)
break;
mdelay(10);
}
mdelay(100);
return ret;
}
static void read_hwmon(const char *name, uint reg, uint size)
{
unsigned char buf[3];
uint ui;
printf("%-8s:", name);
memset(buf, 0, sizeof(buf));
if (gsc_i2c_read(GSC_HWMON_ADDR, reg, 1, buf, size)) {
puts("fRD\n");
} else {
ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
if (reg == GSC_HWMON_TEMP && ui > 0x8000)
ui -= 0xffff;
if (ui == 0xffffff)
puts("invalid\n");
else
printf("%d\n", ui);
}
}
int gsc_info(int verbose)
{
unsigned char buf[16];
i2c_set_bus_num(0);
if (gsc_i2c_read(GSC_SC_ADDR, 0, 1, buf, 16))
return CMD_RET_FAILURE;
printf("GSC: v%d", buf[GSC_SC_FWVER]);
printf(" 0x%04x", buf[GSC_SC_FWCRC] | buf[GSC_SC_FWCRC+1]<<8);
printf(" WDT:%sabled", (buf[GSC_SC_CTRL1] & (1<<GSC_SC_CTRL1_WDEN))
? "en" : "dis");
if (buf[GSC_SC_STATUS] & (1 << GSC_SC_IRQ_WATCHDOG)) {
buf[GSC_SC_STATUS] &= ~(1 << GSC_SC_IRQ_WATCHDOG);
puts(" WDT_RESET");
gsc_i2c_write(GSC_SC_ADDR, GSC_SC_STATUS, 1,
&buf[GSC_SC_STATUS], 1);
}
if (!gsc_i2c_read(GSC_HWMON_ADDR, GSC_HWMON_TEMP, 1, buf, 2)) {
int ui = buf[0] | buf[1]<<8;
if (ui > 0x8000)
ui -= 0xffff;
printf(" board temp at %dC", ui / 10);
}
puts("\n");
if (!verbose)
return CMD_RET_SUCCESS;
read_hwmon("Temp", GSC_HWMON_TEMP, 2);
read_hwmon("VIN", GSC_HWMON_VIN, 3);
read_hwmon("VBATT", GSC_HWMON_VBATT, 3);
read_hwmon("VDD_3P3", GSC_HWMON_VDD_3P3, 3);
read_hwmon("VDD_ARM", GSC_HWMON_VDD_CORE, 3);
read_hwmon("VDD_SOC", GSC_HWMON_VDD_SOC, 3);
read_hwmon("VDD_HIGH", GSC_HWMON_VDD_HIGH, 3);
read_hwmon("VDD_DDR", GSC_HWMON_VDD_DDR, 3);
read_hwmon("VDD_5P0", GSC_HWMON_VDD_5P0, 3);
if (strncasecmp((const char*) ventana_info.model, "GW553", 5))
read_hwmon("VDD_2P5", GSC_HWMON_VDD_2P5, 3);
read_hwmon("VDD_1P8", GSC_HWMON_VDD_1P8, 3);
read_hwmon("VDD_IO2", GSC_HWMON_VDD_IO2, 3);
switch (ventana_info.model[3]) {
case '1': /* GW51xx */
read_hwmon("VDD_IO3", GSC_HWMON_VDD_IO4, 3); /* -C rev */
break;
case '2': /* GW52xx */
break;
case '3': /* GW53xx */
read_hwmon("VDD_IO4", GSC_HWMON_VDD_IO4, 3); /* -C rev */
read_hwmon("VDD_GPS", GSC_HWMON_VDD_IO3, 3);
break;
case '4': /* GW54xx */
read_hwmon("VDD_IO3", GSC_HWMON_VDD_IO4, 3); /* -C rev */
read_hwmon("VDD_GPS", GSC_HWMON_VDD_IO3, 3);
break;
case '5': /* GW55xx */
break;
}
return 0;
}
/*
* The Gateworks System Controller implements a boot
* watchdog (always enabled) as a workaround for IMX6 boot related
* errata such as:
* ERR005768 - no fix scheduled
* ERR006282 - fixed in silicon r1.2
* ERR007117 - fixed in silicon r1.3
* ERR007220 - fixed in silicon r1.3
* ERR007926 - no fix scheduled
* see http://cache.freescale.com/files/32bit/doc/errata/IMX6DQCE.pdf
*
* Disable the boot watchdog
*/
int gsc_boot_wd_disable(void)
{
u8 reg;
i2c_set_bus_num(CONFIG_I2C_GSC);
if (!gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1)) {
reg |= (1 << GSC_SC_CTRL1_WDDIS);
if (!gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
return 0;
}
puts("Error: could not disable GSC Watchdog\n");
return 1;
}
#ifdef CONFIG_CMD_GSC
static int do_gsc_sleep(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
unsigned char reg;
unsigned long secs = 0;
if (argc < 2)
return CMD_RET_USAGE;
secs = simple_strtoul(argv[1], NULL, 10);
printf("GSC Sleeping for %ld seconds\n", secs);
i2c_set_bus_num(0);
reg = (secs >> 24) & 0xff;
if (gsc_i2c_write(GSC_SC_ADDR, 9, 1, &reg, 1))
goto error;
reg = (secs >> 16) & 0xff;
if (gsc_i2c_write(GSC_SC_ADDR, 8, 1, &reg, 1))
goto error;
reg = (secs >> 8) & 0xff;
if (gsc_i2c_write(GSC_SC_ADDR, 7, 1, &reg, 1))
goto error;
reg = secs & 0xff;
if (gsc_i2c_write(GSC_SC_ADDR, 6, 1, &reg, 1))
goto error;
if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
goto error;
reg |= (1 << 2);
if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
goto error;
reg &= ~(1 << 2);
reg |= 0x3;
if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
goto error;
return CMD_RET_SUCCESS;
error:
printf("i2c error\n");
return CMD_RET_FAILURE;
}
static int do_gsc_wd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
unsigned char reg;
if (argc < 2)
return CMD_RET_USAGE;
if (strcasecmp(argv[1], "enable") == 0) {
int timeout = 0;
if (argc > 2)
timeout = simple_strtoul(argv[2], NULL, 10);
i2c_set_bus_num(0);
if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
return CMD_RET_FAILURE;
reg &= ~((1 << GSC_SC_CTRL1_WDEN) | (1 << GSC_SC_CTRL1_WDTIME));
if (timeout == 60)
reg |= (1 << GSC_SC_CTRL1_WDTIME);
else
timeout = 30;
reg |= (1 << GSC_SC_CTRL1_WDEN);
if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
return CMD_RET_FAILURE;
printf("GSC Watchdog enabled with timeout=%d seconds\n",
timeout);
} else if (strcasecmp(argv[1], "disable") == 0) {
i2c_set_bus_num(0);
if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
return CMD_RET_FAILURE;
reg &= ~((1 << GSC_SC_CTRL1_WDEN) | (1 << GSC_SC_CTRL1_WDTIME));
if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, &reg, 1))
return CMD_RET_FAILURE;
printf("GSC Watchdog disabled\n");
} else {
return CMD_RET_USAGE;
}
return CMD_RET_SUCCESS;
}
static int do_gsc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 2)
return gsc_info(1);
if (strcasecmp(argv[1], "wd") == 0)
return do_gsc_wd(cmdtp, flag, --argc, ++argv);
else if (strcasecmp(argv[1], "sleep") == 0)
return do_gsc_sleep(cmdtp, flag, --argc, ++argv);
return CMD_RET_USAGE;
}
U_BOOT_CMD(
gsc, 4, 1, do_gsc, "GSC configuration",
"[wd enable [30|60]]|[wd disable]|[sleep <secs>]\n"
);
#endif /* CONFIG_CMD_GSC */

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2013 Gateworks Corporation
*
* Author: Tim Harvey <tharvey@gateworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __ASSEMBLY__
/* i2c slave addresses */
#define GSC_SC_ADDR 0x20
#define GSC_RTC_ADDR 0x68
#define GSC_HWMON_ADDR 0x29
#define GSC_EEPROM_ADDR 0x51
/* System Controller registers */
enum {
GSC_SC_CTRL0 = 0x00,
GSC_SC_CTRL1 = 0x01,
GSC_SC_STATUS = 0x0a,
GSC_SC_FWCRC = 0x0c,
GSC_SC_FWVER = 0x0e,
};
/* System Controller Control1 bits */
enum {
GSC_SC_CTRL1_WDTIME = 4, /* 1 = 60s timeout, 0 = 30s timeout */
GSC_SC_CTRL1_WDEN = 5, /* 1 = enable, 0 = disable */
GSC_SC_CTRL1_WDDIS = 7, /* 1 = disable boot watchdog */
};
/* System Controller Interrupt bits */
enum {
GSC_SC_IRQ_PB = 0, /* Pushbutton switch */
GSC_SC_IRQ_SECURE = 1, /* Secure Key erase operation complete */
GSC_SC_IRQ_EEPROM_WP = 2, /* EEPROM write violation */
GSC_SC_IRQ_GPIO = 4, /* GPIO change */
GSC_SC_IRQ_TAMPER = 5, /* Tamper detect */
GSC_SC_IRQ_WATCHDOG = 6, /* Watchdog trip */
GSC_SC_IRQ_PBLONG = 7, /* Pushbutton long hold */
};
/* Hardware Monitor registers */
enum {
GSC_HWMON_TEMP = 0x00,
GSC_HWMON_VIN = 0x02,
GSC_HWMON_VDD_3P3 = 0x05,
GSC_HWMON_VBATT = 0x08,
GSC_HWMON_VDD_5P0 = 0x0b,
GSC_HWMON_VDD_CORE = 0x0e,
GSC_HWMON_VDD_HIGH = 0x14,
GSC_HWMON_VDD_DDR = 0x17,
GSC_HWMON_VDD_SOC = 0x11,
GSC_HWMON_VDD_1P8 = 0x1d,
GSC_HWMON_VDD_IO2 = 0x20,
GSC_HWMON_VDD_2P5 = 0x23,
GSC_HWMON_VDD_IO3 = 0x26,
GSC_HWMON_VDD_IO4 = 0x29,
};
/*
* I2C transactions to the GSC are done via these functions which
* perform retries in the case of a busy GSC NAK'ing the transaction
*/
int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len);
int gsc_i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len);
int gsc_info(int verbose);
int gsc_boot_wd_disable(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,613 @@
/*
* Copyright (C) 2014 Gateworks Corporation
* Author: Tim Harvey <tharvey@gateworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/crm_regs.h>
#include <asm/arch/mx6-ddr.h>
#include <asm/arch/mx6-pins.h>
#include <asm/arch/sys_proto.h>
#include <asm/imx-common/boot_mode.h>
#include <asm/imx-common/iomux-v3.h>
#include <asm/imx-common/mxc_i2c.h>
#include <environment.h>
#include <i2c.h>
#include <spl.h>
#include "gsc.h"
#include "common.h"
DECLARE_GLOBAL_DATA_PTR;
#define RTT_NOM_120OHM /* use 120ohm Rtt_nom vs 60ohm (lower power) */
#define GSC_EEPROM_DDR_SIZE 0x2B /* enum (512,1024,2048) MB */
#define GSC_EEPROM_DDR_WIDTH 0x2D /* enum (32,64) bit */
/* configure MX6Q/DUAL mmdc DDR io registers */
struct mx6dq_iomux_ddr_regs mx6dq_ddr_ioregs = {
/* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */
.dram_sdclk_0 = 0x00020030,
.dram_sdclk_1 = 0x00020030,
.dram_cas = 0x00020030,
.dram_ras = 0x00020030,
.dram_reset = 0x00020030,
/* SDCKE[0:1]: 100k pull-up */
.dram_sdcke0 = 0x00003000,
.dram_sdcke1 = 0x00003000,
/* SDBA2: pull-up disabled */
.dram_sdba2 = 0x00000000,
/* SDODT[0:1]: 100k pull-up, 40 ohm */
.dram_sdodt0 = 0x00003030,
.dram_sdodt1 = 0x00003030,
/* SDQS[0:7]: Differential input, 40 ohm */
.dram_sdqs0 = 0x00000030,
.dram_sdqs1 = 0x00000030,
.dram_sdqs2 = 0x00000030,
.dram_sdqs3 = 0x00000030,
.dram_sdqs4 = 0x00000030,
.dram_sdqs5 = 0x00000030,
.dram_sdqs6 = 0x00000030,
.dram_sdqs7 = 0x00000030,
/* DQM[0:7]: Differential input, 40 ohm */
.dram_dqm0 = 0x00020030,
.dram_dqm1 = 0x00020030,
.dram_dqm2 = 0x00020030,
.dram_dqm3 = 0x00020030,
.dram_dqm4 = 0x00020030,
.dram_dqm5 = 0x00020030,
.dram_dqm6 = 0x00020030,
.dram_dqm7 = 0x00020030,
};
/* configure MX6Q/DUAL mmdc GRP io registers */
struct mx6dq_iomux_grp_regs mx6dq_grp_ioregs = {
/* DDR3 */
.grp_ddr_type = 0x000c0000,
.grp_ddrmode_ctl = 0x00020000,
/* disable DDR pullups */
.grp_ddrpke = 0x00000000,
/* ADDR[00:16], SDBA[0:1]: 40 ohm */
.grp_addds = 0x00000030,
/* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */
.grp_ctlds = 0x00000030,
/* DATA[00:63]: Differential input, 40 ohm */
.grp_ddrmode = 0x00020000,
.grp_b0ds = 0x00000030,
.grp_b1ds = 0x00000030,
.grp_b2ds = 0x00000030,
.grp_b3ds = 0x00000030,
.grp_b4ds = 0x00000030,
.grp_b5ds = 0x00000030,
.grp_b6ds = 0x00000030,
.grp_b7ds = 0x00000030,
};
/* configure MX6SOLO/DUALLITE mmdc DDR io registers */
struct mx6sdl_iomux_ddr_regs mx6sdl_ddr_ioregs = {
/* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */
.dram_sdclk_0 = 0x00020030,
.dram_sdclk_1 = 0x00020030,
.dram_cas = 0x00020030,
.dram_ras = 0x00020030,
.dram_reset = 0x00020030,
/* SDCKE[0:1]: 100k pull-up */
.dram_sdcke0 = 0x00003000,
.dram_sdcke1 = 0x00003000,
/* SDBA2: pull-up disabled */
.dram_sdba2 = 0x00000000,
/* SDODT[0:1]: 100k pull-up, 40 ohm */
.dram_sdodt0 = 0x00003030,
.dram_sdodt1 = 0x00003030,
/* SDQS[0:7]: Differential input, 40 ohm */
.dram_sdqs0 = 0x00000030,
.dram_sdqs1 = 0x00000030,
.dram_sdqs2 = 0x00000030,
.dram_sdqs3 = 0x00000030,
.dram_sdqs4 = 0x00000030,
.dram_sdqs5 = 0x00000030,
.dram_sdqs6 = 0x00000030,
.dram_sdqs7 = 0x00000030,
/* DQM[0:7]: Differential input, 40 ohm */
.dram_dqm0 = 0x00020030,
.dram_dqm1 = 0x00020030,
.dram_dqm2 = 0x00020030,
.dram_dqm3 = 0x00020030,
.dram_dqm4 = 0x00020030,
.dram_dqm5 = 0x00020030,
.dram_dqm6 = 0x00020030,
.dram_dqm7 = 0x00020030,
};
/* configure MX6SOLO/DUALLITE mmdc GRP io registers */
struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = {
/* DDR3 */
.grp_ddr_type = 0x000c0000,
/* SDQS[0:7]: Differential input, 40 ohm */
.grp_ddrmode_ctl = 0x00020000,
/* disable DDR pullups */
.grp_ddrpke = 0x00000000,
/* ADDR[00:16], SDBA[0:1]: 40 ohm */
.grp_addds = 0x00000030,
/* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */
.grp_ctlds = 0x00000030,
/* DATA[00:63]: Differential input, 40 ohm */
.grp_ddrmode = 0x00020000,
.grp_b0ds = 0x00000030,
.grp_b1ds = 0x00000030,
.grp_b2ds = 0x00000030,
.grp_b3ds = 0x00000030,
.grp_b4ds = 0x00000030,
.grp_b5ds = 0x00000030,
.grp_b6ds = 0x00000030,
.grp_b7ds = 0x00000030,
};
/* MT41K64M16JT-125 (1Gb density) */
static struct mx6_ddr3_cfg mt41k64m16jt_125 = {
.mem_speed = 1600,
.density = 1,
.width = 16,
.banks = 8,
.rowaddr = 13,
.coladdr = 10,
.pagesz = 2,
.trcd = 1375,
.trcmin = 4875,
.trasmin = 3500,
};
/* MT41K128M16JT-125 (2Gb density) */
static struct mx6_ddr3_cfg mt41k128m16jt_125 = {
.mem_speed = 1600,
.density = 2,
.width = 16,
.banks = 8,
.rowaddr = 14,
.coladdr = 10,
.pagesz = 2,
.trcd = 1375,
.trcmin = 4875,
.trasmin = 3500,
};
/* MT41K256M16HA-125 (4Gb density) */
static struct mx6_ddr3_cfg mt41k256m16ha_125 = {
.mem_speed = 1600,
.density = 4,
.width = 16,
.banks = 8,
.rowaddr = 15,
.coladdr = 10,
.pagesz = 2,
.trcd = 1375,
.trcmin = 4875,
.trasmin = 3500,
};
/* MT41K512M16HA-125 (8Gb density) */
static struct mx6_ddr3_cfg mt41k512m16ha_125 = {
.mem_speed = 1600,
.density = 8,
.width = 16,
.banks = 8,
.rowaddr = 16,
.coladdr = 10,
.pagesz = 2,
.trcd = 1375,
.trcmin = 4875,
.trasmin = 3500,
};
/*
* calibration - these are the various CPU/DDR3 combinations we support
*/
static struct mx6_mmdc_calibration mx6sdl_64x16_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x004C004E,
.p0_mpwldectrl1 = 0x00440044,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x42440247,
.p0_mpdgctrl1 = 0x02310232,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x45424746,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x33382C31,
};
static struct mx6_mmdc_calibration mx6dq_256x16_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x001B0016,
.p0_mpwldectrl1 = 0x000C000E,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x4324033A,
.p0_mpdgctrl1 = 0x00000000,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x40403438,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x40403D36,
};
static struct mx6_mmdc_calibration mx6sdl_256x16_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x00420043,
.p0_mpwldectrl1 = 0x0016001A,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x4238023B,
.p0_mpdgctrl1 = 0x00000000,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x40404849,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x40402E2F,
};
static struct mx6_mmdc_calibration mx6dq_128x32_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x00190017,
.p0_mpwldectrl1 = 0x00140026,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x43380347,
.p0_mpdgctrl1 = 0x433C034D,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x3C313539,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x36393C39,
};
static struct mx6_mmdc_calibration mx6sdl_128x32_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x003C003C,
.p0_mpwldectrl1 = 0x001F002A,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x42410244,
.p0_mpdgctrl1 = 0x4234023A,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x484A4C4B,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x33342B32,
};
static struct mx6_mmdc_calibration mx6dq_128x64_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x00190017,
.p0_mpwldectrl1 = 0x00140026,
.p1_mpwldectrl0 = 0x0021001C,
.p1_mpwldectrl1 = 0x0011001D,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x43380347,
.p0_mpdgctrl1 = 0x433C034D,
.p1_mpdgctrl0 = 0x032C0324,
.p1_mpdgctrl1 = 0x03310232,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x3C313539,
.p1_mprddlctl = 0x37343141,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x36393C39,
.p1_mpwrdlctl = 0x42344438,
};
static struct mx6_mmdc_calibration mx6sdl_128x64_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x003C003C,
.p0_mpwldectrl1 = 0x001F002A,
.p1_mpwldectrl0 = 0x00330038,
.p1_mpwldectrl1 = 0x0022003F,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x42410244,
.p0_mpdgctrl1 = 0x4234023A,
.p1_mpdgctrl0 = 0x022D022D,
.p1_mpdgctrl1 = 0x021C0228,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x484A4C4B,
.p1_mprddlctl = 0x4B4D4E4B,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x33342B32,
.p1_mpwrdlctl = 0x3933332B,
};
static struct mx6_mmdc_calibration mx6dq_256x32_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x001E001A,
.p0_mpwldectrl1 = 0x0026001F,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x43370349,
.p0_mpdgctrl1 = 0x032D0327,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x3D303639,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x32363934,
};
static struct mx6_mmdc_calibration mx6sdl_256x32_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0X00480047,
.p0_mpwldectrl1 = 0X003D003F,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0X423E0241,
.p0_mpdgctrl1 = 0X022B022C,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0X49454A4A,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0X2E372C32,
};
static struct mx6_mmdc_calibration mx6dq_256x64_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0X00220021,
.p0_mpwldectrl1 = 0X00200030,
.p1_mpwldectrl0 = 0X002D0027,
.p1_mpwldectrl1 = 0X00150026,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x43330342,
.p0_mpdgctrl1 = 0x0339034A,
.p1_mpdgctrl0 = 0x032F0325,
.p1_mpdgctrl1 = 0x032F022E,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0X3A2E3437,
.p1_mprddlctl = 0X35312F3F,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0X33363B37,
.p1_mpwrdlctl = 0X40304239,
};
static struct mx6_mmdc_calibration mx6dq_512x32_mmdc_calib = {
/* write leveling calibration determine */
.p0_mpwldectrl0 = 0x002A0025,
.p0_mpwldectrl1 = 0x003A002A,
/* Read DQS Gating calibration */
.p0_mpdgctrl0 = 0x43430356,
.p0_mpdgctrl1 = 0x033C0335,
/* Read Calibration: DQS delay relative to DQ read access */
.p0_mprddlctl = 0x4B373F42,
/* Write Calibration: DQ/DM delay relative to DQS write access */
.p0_mpwrdlctl = 0x303E3C36,
};
static void spl_dram_init(int width, int size_mb, int board_model)
{
struct mx6_ddr3_cfg *mem = NULL;
struct mx6_mmdc_calibration *calib = NULL;
struct mx6_ddr_sysinfo sysinfo = {
/* width of data bus:0=16,1=32,2=64 */
.dsize = width/32,
/* config for full 4GB range so that get_mem_size() works */
.cs_density = 32, /* 32Gb per CS */
/* single chip select */
.ncs = 1,
.cs1_mirror = 0,
.rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */
#ifdef RTT_NOM_120OHM
.rtt_nom = 2 /*DDR3_RTT_120_OHM*/, /* RTT_Nom = RZQ/2 */
#else
.rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */
#endif
.walat = 1, /* Write additional latency */
.ralat = 5, /* Read additional latency */
.mif3_mode = 3, /* Command prediction working mode */
.bi_on = 1, /* Bank interleaving enabled */
.sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */
.rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */
.pd_fast_exit = 1, /* enable precharge power-down fast exit */
.ddr_type = DDR_TYPE_DDR3,
};
/*
* MMDC Calibration requires the following data:
* mx6_mmdc_calibration - board-specific calibration (routing delays)
* these calibration values depend on board routing, SoC, and DDR
* mx6_ddr_sysinfo - board-specific memory architecture (width/cs/etc)
* mx6_ddr_cfg - chip specific timing/layout details
*/
if (width == 16 && size_mb == 128) {
mem = &mt41k64m16jt_125;
if (is_cpu_type(MXC_CPU_MX6Q))
;
else
calib = &mx6sdl_64x16_mmdc_calib;
debug("1gB density\n");
} else if (width == 16 && size_mb == 256) {
/* 1x 2Gb density chip - same calib as 2x 2Gb */
mem = &mt41k128m16jt_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_128x32_mmdc_calib;
else
calib = &mx6sdl_128x32_mmdc_calib;
debug("2gB density\n");
} else if (width == 16 && size_mb == 512) {
mem = &mt41k256m16ha_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_256x16_mmdc_calib;
else
calib = &mx6sdl_256x16_mmdc_calib;
debug("4gB density\n");
} else if (width == 32 && size_mb == 256) {
/* Same calib as width==16, size==128 */
mem = &mt41k64m16jt_125;
if (is_cpu_type(MXC_CPU_MX6Q))
;
else
calib = &mx6sdl_64x16_mmdc_calib;
debug("1gB density\n");
} else if (width == 32 && size_mb == 512) {
mem = &mt41k128m16jt_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_128x32_mmdc_calib;
else
calib = &mx6sdl_128x32_mmdc_calib;
debug("2gB density\n");
} else if (width == 32 && size_mb == 1024) {
mem = &mt41k256m16ha_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_256x32_mmdc_calib;
else
calib = &mx6sdl_256x32_mmdc_calib;
debug("4gB density\n");
} else if (width == 32 && size_mb == 2048) {
mem = &mt41k512m16ha_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_512x32_mmdc_calib;
debug("8gB density\n");
} else if (width == 64 && size_mb == 512) {
mem = &mt41k64m16jt_125;
debug("1gB density\n");
} else if (width == 64 && size_mb == 1024) {
mem = &mt41k128m16jt_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_128x64_mmdc_calib;
else
calib = &mx6sdl_128x64_mmdc_calib;
debug("2gB density\n");
} else if (width == 64 && size_mb == 2048) {
mem = &mt41k256m16ha_125;
if (is_cpu_type(MXC_CPU_MX6Q))
calib = &mx6dq_256x64_mmdc_calib;
debug("4gB density\n");
}
if (!(mem && calib)) {
puts("Error: Invalid Calibration/Board Configuration\n");
printf("MEM : %s\n", mem ? "OKAY" : "NULL");
printf("CALIB : %s\n", calib ? "OKAY" : "NULL");
printf("CPUTYPE: %s\n",
is_cpu_type(MXC_CPU_MX6Q) ? "IMX6Q" : "IMX6DL");
printf("SIZE_MB: %d\n", size_mb);
printf("WIDTH : %d\n", width);
hang();
}
if (is_cpu_type(MXC_CPU_MX6Q))
mx6dq_dram_iocfg(width, &mx6dq_ddr_ioregs,
&mx6dq_grp_ioregs);
else
mx6sdl_dram_iocfg(width, &mx6sdl_ddr_ioregs,
&mx6sdl_grp_ioregs);
mx6_dram_cfg(&sysinfo, calib, mem);
}
static void ccgr_init(void)
{
struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
writel(0x00C03F3F, &ccm->CCGR0);
writel(0x0030FC03, &ccm->CCGR1);
writel(0x0FFFC000, &ccm->CCGR2);
writel(0x3FF00000, &ccm->CCGR3);
writel(0xFFFFF300, &ccm->CCGR4); /* enable NAND/GPMI/BCH clks */
writel(0x0F0000C3, &ccm->CCGR5);
writel(0x000003FF, &ccm->CCGR6);
}
static void gpr_init(void)
{
struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
/* enable AXI cache for VDOA/VPU/IPU */
writel(0xF00000CF, &iomux->gpr[4]);
/* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
writel(0x007F007F, &iomux->gpr[6]);
writel(0x007F007F, &iomux->gpr[7]);
}
/*
* called from C runtime startup code (arch/arm/lib/crt0.S:_main)
* - we have a stack and a place to store GD, both in SRAM
* - no variable global data is available
*/
void board_init_f(ulong dummy)
{
struct ventana_board_info ventana_info;
int board_model;
/* setup clock gating */
ccgr_init();
/* setup AIPS and disable watchdog */
arch_cpu_init();
/* setup AXI */
gpr_init();
/* iomux and setup of i2c */
setup_iomux_uart();
setup_ventana_i2c();
/* setup GP timer */
timer_init();
/* UART clocks enabled and gd valid - init serial console */
preloader_console_init();
/* read/validate EEPROM info to determine board model and SDRAM cfg */
board_model = read_eeprom(CONFIG_I2C_GSC, &ventana_info);
/* configure model-specific gpio */
setup_iomux_gpio(board_model, &ventana_info);
/* provide some some default: 32bit 128MB */
if (GW_UNKNOWN == board_model)
hang();
/* configure MMDC for SDRAM width/size and per-model calibration */
spl_dram_init(8 << ventana_info.sdram_width,
16 << ventana_info.sdram_size,
board_model);
/* Clear the BSS. */
memset(__bss_start, 0, __bss_end - __bss_start);
}
/* called from board_init_r after gd setup if CONFIG_SPL_BOARD_INIT defined */
/* its our chance to print info about boot device */
void spl_board_init(void)
{
/* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 */
u32 boot_device = spl_boot_device();
switch (boot_device) {
case BOOT_DEVICE_MMC1:
puts("Booting from MMC\n");
break;
case BOOT_DEVICE_NAND:
puts("Booting from NAND\n");
break;
case BOOT_DEVICE_SATA:
puts("Booting from SATA\n");
break;
default:
puts("Unknown boot device\n");
}
/* PMIC init */
setup_pmic();
}
#ifdef CONFIG_SPL_OS_BOOT
/* return 1 if we wish to boot to uboot vs os (falcon mode) */
int spl_start_uboot(void)
{
unsigned char ret = 1;
debug("%s\n", __func__);
#ifdef CONFIG_SPL_ENV_SUPPORT
env_init();
env_relocate_spec();
debug("boot_os=%s\n", getenv("boot_os"));
if (getenv_yesno("boot_os") == 1)
ret = 0;
#else
/* use i2c-0:0x50:0x00 for falcon boot mode (0=linux, else uboot) */
i2c_set_bus_num(0);
gsc_i2c_read(0x50, 0x0, 1, &ret, 1);
#endif
if (!ret)
gsc_boot_wd_disable();
debug("%s booting %s\n", __func__, ret ? "uboot" : "linux");
return ret;
}
#endif

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2013 Gateworks Corporation
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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: (16 << n) MB */
u8 sdram_speed; /* 0x2C: (33.333 * n) MHz */
u8 sdram_width; /* 0x2D: (8 << n) bit */
/* cpu config */
u8 cpu_speed; /* 0x2E: (33.333 * n) MHz */
u8 cpu_type; /* 0x2F: 7=imx6q, 8=imx6dl */
u8 model[16]; /* 0x30: model string */
/* FLASH config */
u8 nand_flash_size; /* 0x40: (8 << (n-1)) MB */
u8 spi_flash_size; /* 0x41: (4 << (n-1)) MB */
/* Config1: SoC Peripherals */
u8 config[8]; /* 0x42: loading options */
u8 res3[4]; /* 0x4A */
u8 chksum[2]; /* 0x4E */
};
/* config bits */
enum {
EECONFIG_ETH0,
EECONFIG_ETH1,
EECONFIG_HDMI_OUT,
EECONFIG_SATA,
EECONFIG_PCIE,
EECONFIG_SSI0,
EECONFIG_SSI1,
EECONFIG_LCD,
EECONFIG_LVDS0,
EECONFIG_LVDS1,
EECONFIG_USB0,
EECONFIG_USB1,
EECONFIG_SD0,
EECONFIG_SD1,
EECONFIG_SD2,
EECONFIG_SD3,
EECONFIG_UART0,
EECONFIG_UART1,
EECONFIG_UART2,
EECONFIG_UART3,
EECONFIG_UART4,
EECONFIG_IPU0,
EECONFIG_IPU1,
EECONFIG_FLEXCAN,
EECONFIG_MIPI_DSI,
EECONFIG_MIPI_CSI,
EECONFIG_TZASC0,
EECONFIG_TZASC1,
EECONFIG_I2C0,
EECONFIG_I2C1,
EECONFIG_I2C2,
EECONFIG_VPU,
EECONFIG_CSI0,
EECONFIG_CSI1,
EECONFIG_CAAM,
EECONFIG_MEZZ,
EECONFIG_RES1,
EECONFIG_RES2,
EECONFIG_RES3,
EECONFIG_RES4,
EECONFIG_ESPCI0,
EECONFIG_ESPCI1,
EECONFIG_ESPCI2,
EECONFIG_ESPCI3,
EECONFIG_ESPCI4,
EECONFIG_ESPCI5,
EECONFIG_RES5,
EECONFIG_RES6,
EECONFIG_GPS,
EECONFIG_SPIFL0,
EECONFIG_SPIFL1,
EECONFIG_GSPBATT,
EECONFIG_HDMI_IN,
EECONFIG_VID_OUT,
EECONFIG_VID_IN,
EECONFIG_NAND,
EECONFIG_RES8,
EECONFIG_RES9,
EECONFIG_RES10,
EECONFIG_RES11,
EECONFIG_RES12,
EECONFIG_RES13,
EECONFIG_RES14,
EECONFIG_RES15,
};
enum {
GW54proto, /* original GW5400-A prototype */
GW51xx,
GW52xx,
GW53xx,
GW54xx,
GW551x,
GW552x,
GW553x,
GW_UNKNOWN,
GW_BADCRC,
};
/* config items */
struct ventana_eeprom_config {
const char *name; /* name of item */
const char *dtalias; /* name of dt node to remove if not set */
int bit; /* bit within config */
};
extern struct ventana_eeprom_config econfig[];
extern struct ventana_board_info ventana_info;
int read_eeprom(int bus, struct ventana_board_info *);
#endif