diff options
Diffstat (limited to 'roms/u-boot/board/gateworks/gw_ventana')
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/Kconfig | 28 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/MAINTAINERS | 56 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/Makefile | 11 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/README | 320 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/common.c | 1743 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/common.h | 97 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/eeprom.c | 267 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/gsc.c | 371 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/gsc.h | 72 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/gw_ventana.c | 1223 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/gw_ventana_spl.c | 787 | ||||
-rw-r--r-- | roms/u-boot/board/gateworks/gw_ventana/ventana_eeprom.h | 140 |
12 files changed, 5115 insertions, 0 deletions
diff --git a/roms/u-boot/board/gateworks/gw_ventana/Kconfig b/roms/u-boot/board/gateworks/gw_ventana/Kconfig new file mode 100644 index 000000000..fee910ca8 --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/Kconfig @@ -0,0 +1,28 @@ +if TARGET_GW_VENTANA + +config DM_GPIO + default y + +config SYS_BOARD + default "gw_ventana" + +config SYS_VENDOR + default "gateworks" + +config SYS_CONFIG_NAME + default "gw_ventana" + +config CMD_EECONFIG + bool "Enable the 'econfig' command" + help + Provides access to EEPROM configuration on Gateworks Ventana + +config CMD_GSC + bool "Enable the 'gsc' command" + help + Provides access to the GSC configuration: + + gsc sleep - sleeps for a period of seconds + gsc wd - enables / disables the watchdog + +endif diff --git a/roms/u-boot/board/gateworks/gw_ventana/MAINTAINERS b/roms/u-boot/board/gateworks/gw_ventana/MAINTAINERS new file mode 100644 index 000000000..1619d23c8 --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/MAINTAINERS @@ -0,0 +1,56 @@ +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_nand_defconfig +F: configs/gwventana_emmc_defconfig +F: configs/gwventana_gw5904_defconfig +F: arch/arm/dts/imx6dl-gw51xx.dts +F: arch/arm/dts/imx6dl-gw52xx.dts +F: arch/arm/dts/imx6dl-gw53xx.dts +F: arch/arm/dts/imx6dl-gw54xx.dts +F: arch/arm/dts/imx6dl-gw551x.dts +F: arch/arm/dts/imx6dl-gw552x.dts +F: arch/arm/dts/imx6dl-gw553x.dts +F: arch/arm/dts/imx6dl-gw560x.dts +F: arch/arm/dts/imx6dl-gw5903.dts +F: arch/arm/dts/imx6dl-gw5904.dts +F: arch/arm/dts/imx6dl-gw5905.dts +F: arch/arm/dts/imx6dl-gw5907.dts +F: arch/arm/dts/imx6dl-gw5910.dts +F: arch/arm/dts/imx6dl-gw5912.dts +F: arch/arm/dts/imx6dl-gw5913.dts +F: arch/arm/dts/imx6qdl-gw51xx.dtsi +F: arch/arm/dts/imx6qdl-gw52xx.dtsi +F: arch/arm/dts/imx6qdl-gw53xx.dtsi +F: arch/arm/dts/imx6qdl-gw54xx.dtsi +F: arch/arm/dts/imx6qdl-gw551x.dtsi +F: arch/arm/dts/imx6qdl-gw552x.dtsi +F: arch/arm/dts/imx6qdl-gw553x.dtsi +F: arch/arm/dts/imx6qdl-gw560x.dtsi +F: arch/arm/dts/imx6qdl-gw5903.dtsi +F: arch/arm/dts/imx6qdl-gw5904.dtsi +F: arch/arm/dts/imx6qdl-gw5905.dtsi +F: arch/arm/dts/imx6qdl-gw5907.dtsi +F: arch/arm/dts/imx6qdl-gw5910.dtsi +F: arch/arm/dts/imx6qdl-gw5912.dtsi +F: arch/arm/dts/imx6qdl-gw5913.dtsi +F: arch/arm/dts/imx6q-gw51xx.dts +F: arch/arm/dts/imx6q-gw52xx.dts +F: arch/arm/dts/imx6q-gw53xx.dts +F: arch/arm/dts/imx6q-gw5400-a.dts +F: arch/arm/dts/imx6q-gw54xx.dts +F: arch/arm/dts/imx6q-gw551x.dts +F: arch/arm/dts/imx6q-gw552x.dts +F: arch/arm/dts/imx6q-gw553x.dts +F: arch/arm/dts/imx6q-gw560x.dts +F: arch/arm/dts/imx6q-gw5901.dts +F: arch/arm/dts/imx6q-gw5902.dts +F: arch/arm/dts/imx6q-gw5903.dts +F: arch/arm/dts/imx6q-gw5904.dts +F: arch/arm/dts/imx6q-gw5905.dts +F: arch/arm/dts/imx6q-gw5907.dts +F: arch/arm/dts/imx6q-gw5910.dts +F: arch/arm/dts/imx6q-gw5912.dts +F: arch/arm/dts/imx6q-gw5913.dts diff --git a/roms/u-boot/board/gateworks/gw_ventana/Makefile b/roms/u-boot/board/gateworks/gw_ventana/Makefile new file mode 100644 index 000000000..8fa691aef --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/Makefile @@ -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 + diff --git a/roms/u-boot/board/gateworks/gw_ventana/README b/roms/u-boot/board/gateworks/gw_ventana/README new file mode 100644 index 000000000..57c64a1b2 --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/README @@ -0,0 +1,320 @@ +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: + +For NAND FLASH based boards: + make gwventana_nand_config + make + +For EMMC FLASH based boards: + make gwventana_emmc_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 MMC (eMMC/microSD) +--------------------------------- + +When the IMX6 eFUSE settings have been factory programmed to boot from +MMC 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 an MMC device 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 MMC, ie /dev/mmcblk0): + + 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 diff --git a/roms/u-boot/board/gateworks/gw_ventana/common.c b/roms/u-boot/board/gateworks/gw_ventana/common.c new file mode 100644 index 000000000..4627a156f --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/common.c @@ -0,0 +1,1743 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Gateworks Corporation + * + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <log.h> +#include <asm/arch/clock.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/sys_proto.h> +#include <asm/gpio.h> +#include <asm/mach-imx/mxc_i2c.h> +#include <env.h> +#include <fsl_esdhc_imx.h> +#include <hwconfig.h> +#include <linux/delay.h> +#include <power/pmic.h> +#include <power/ltc3676_pmic.h> +#include <power/pfuze100_pmic.h> + +#include "common.h" + +/* 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(uart2_pads); +} + +/* MMC */ +static iomux_v3_cfg_t const gw5904_emmc_pads[] = { + IOMUX_PADS(PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT4__SD3_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT5__SD3_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT6__SD3_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT7__SD3_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_RST__SD3_RESET | MUX_PAD_CTRL(USDHC_PAD_CTRL)), +}; +/* 4-bit microSD on SD2 */ +static iomux_v3_cfg_t const gw5904_mmc_pads[] = { + IOMUX_PADS(PAD_SD2_CLK__SD2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_CMD__SD2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT0__SD2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT1__SD2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT2__SD2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT3__SD2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + /* CD */ + IOMUX_PADS(PAD_NANDF_CS0__GPIO6_IO11 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), +}; +/* 8-bit eMMC on SD2/NAND */ +static iomux_v3_cfg_t const gw560x_emmc_sd2_pads[] = { + IOMUX_PADS(PAD_SD2_CLK__SD2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_CMD__SD2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT0__SD2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT1__SD2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT2__SD2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD2_DAT3__SD2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D4__SD2_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D5__SD2_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D6__SD2_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_NANDF_D7__SD2_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), +}; + +static iomux_v3_cfg_t const usdhc3_pads[] = { + IOMUX_PADS(PAD_SD3_CLK__SD3_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_CMD__SD3_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT0__SD3_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT1__SD3_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT2__SD3_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT3__SD3_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT5__GPIO7_IO00 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), +}; + +/* + * I2C pad configs: + * I2C1: GSC + * I2C2: PMIC,PCIe Switch,Clock,Mezz + * I2C3: Multimedia/Expansion + */ +static struct i2c_pads_info mx6q_i2c_pad_info[] = { + { + .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) + } + }, { + .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) + } + }, { + .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_info[] = { + { + .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) + } + }, { + .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) + } + }, { + .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(int i2c) +{ + struct i2c_pads_info *p; + + if (is_cpu_type(MXC_CPU_MX6Q)) + p = &mx6q_i2c_pad_info[i2c]; + else + p = &mx6dl_i2c_pad_info[i2c]; + + setup_i2c(i2c, CONFIG_SYS_I2C_SPEED, 0x7f, p); +} + +/* + * Baseboard specific GPIO + */ +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[] = { + /* SD3_VSELECT */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* RS232_EN# */ + IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | DIO_PAD_CFG), + /* 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[] = { + /* SD3_VSELECT */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* RS232_EN# */ + IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | DIO_PAD_CFG), + /* 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[] = { + /* SD3_VSELECT */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* RS232_EN# */ + IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | DIO_PAD_CFG), + /* 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[] = { + /* SD3_VSELECT */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* 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), +}; + +static iomux_v3_cfg_t const gw560x_gpio_pads[] = { + /* RS232_EN# */ + IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | 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), + /* VID_EN */ + IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG), + /* PCI_RST# */ + IOMUX_PADS(PAD_DISP0_DAT10__GPIO4_IO31 | 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), + /* USBH2_PEN (OTG) */ + IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG), + /* 12V0_PWR_EN */ + IOMUX_PADS(PAD_DISP0_DAT5__GPIO4_IO26 | DIO_PAD_CFG), +}; + +static iomux_v3_cfg_t const gw5901_gpio_pads[] = { + /* MX6_LOCLED# */ + IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG), + /* ETH1_EN */ + IOMUX_PADS(PAD_GPIO_1__GPIO1_IO01 | DIO_PAD_CFG), + /* CAN_STBY */ + IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG), + /* PCI_RST# */ + IOMUX_PADS(PAD_ENET_TXD1__GPIO1_IO29 | DIO_PAD_CFG), + /* PMIC reset */ + IOMUX_PADS(PAD_DISP0_DAT8__WDOG1_B | DIO_PAD_CFG), + /* COM_CFGA/B/C/D */ + IOMUX_PADS(PAD_DISP0_DAT20__GPIO5_IO14 | DIO_PAD_CFG), + IOMUX_PADS(PAD_DISP0_DAT21__GPIO5_IO15 | DIO_PAD_CFG), + IOMUX_PADS(PAD_DISP0_DAT22__GPIO5_IO16 | DIO_PAD_CFG), + IOMUX_PADS(PAD_DISP0_DAT23__GPIO5_IO17 | DIO_PAD_CFG), + /* ETI_IRQ# */ + IOMUX_PADS(PAD_GPIO_5__GPIO1_IO05 | DIO_PAD_CFG), + /* DIO_IRQ# */ + IOMUX_PADS(PAD_GPIO_7__GPIO1_IO07 | DIO_PAD_CFG), + /* FIBER_SIGDET */ + IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09 | DIO_PAD_CFG), +}; + +static iomux_v3_cfg_t const gw5902_gpio_pads[] = { + /* MX6_LOCLED# */ + IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG), + /* CAN1_STBY */ + IOMUX_PADS(PAD_GPIO_2__GPIO1_IO02 | DIO_PAD_CFG), + /* CAN2_STBY */ + IOMUX_PADS(PAD_SD3_CLK__GPIO7_IO03 | DIO_PAD_CFG), + /* UART1_EN# */ + IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | DIO_PAD_CFG), + /* PCI_RST# */ + IOMUX_PADS(PAD_GPIO_0__GPIO1_IO00 | DIO_PAD_CFG), + /* 5V_UVLO */ + IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG), + /* ETI_IRQ# */ + IOMUX_PADS(PAD_GPIO_5__GPIO1_IO05 | DIO_PAD_CFG), + /* DIO_IRQ# */ + IOMUX_PADS(PAD_GPIO_7__GPIO1_IO07 | DIO_PAD_CFG), + /* USBOTG_PEN */ + IOMUX_PADS(PAD_EIM_D23__GPIO3_IO23 | DIO_PAD_CFG), +}; + +static iomux_v3_cfg_t const gw5903_gpio_pads[] = { + /* BKLT_12VEN */ + IOMUX_PADS(PAD_GPIO_7__GPIO1_IO07 | DIO_PAD_CFG), + /* EMMY_PDN# */ + IOMUX_PADS(PAD_NANDF_D2__GPIO2_IO02 | DIO_PAD_CFG), + /* EMMY_CFG1# */ + IOMUX_PADS(PAD_NANDF_D3__GPIO2_IO03 | DIO_PAD_CFG), + /* EMMY_CFG1# */ + IOMUX_PADS(PAD_NANDF_D4__GPIO2_IO04 | DIO_PAD_CFG), + /* USBH1_PEN (EHCI) */ + IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG), + /* USBH2_PEN (OTG) */ + IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | DIO_PAD_CFG), + /* USBDPC_PEN */ + IOMUX_PADS(PAD_KEY_ROW0__GPIO4_IO07 | DIO_PAD_CFG), + /* TOUCH_RST */ + IOMUX_PADS(PAD_KEY_COL1__GPIO4_IO08 | DIO_PAD_CFG), + /* AUDIO_RST# */ + IOMUX_PADS(PAD_DISP0_DAT23__GPIO5_IO17 | DIO_PAD_CFG), + /* UART1_TEN# */ + IOMUX_PADS(PAD_CSI0_DAT12__GPIO5_IO30 | DIO_PAD_CFG), + /* MX6_LOCLED# */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* LVDS_BKLEN # */ + IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG), + /* RGMII_PDWN# */ + IOMUX_PADS(PAD_ENET_CRS_DV__GPIO1_IO25 | DIO_PAD_CFG), + /* TOUCH_IRQ# */ + IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG), + /* TOUCH_RST# */ + IOMUX_PADS(PAD_KEY_COL1__GPIO4_IO08 | DIO_PAD_CFG), +}; + +static iomux_v3_cfg_t const gw5904_gpio_pads[] = { + /* 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), + /* UART_RS485 */ + IOMUX_PADS(PAD_DISP0_DAT2__GPIO4_IO23 | DIO_PAD_CFG), + /* UART_HALF */ + IOMUX_PADS(PAD_DISP0_DAT3__GPIO4_IO24 | DIO_PAD_CFG), + /* SKT1_WDIS# */ + IOMUX_PADS(PAD_DISP0_DAT17__GPIO5_IO11 | DIO_PAD_CFG), + /* SKT1_RST# */ + IOMUX_PADS(PAD_DISP0_DAT18__GPIO5_IO12 | DIO_PAD_CFG), + /* SKT2_WDIS# */ + IOMUX_PADS(PAD_DISP0_DAT19__GPIO5_IO13 | DIO_PAD_CFG), + /* SKT2_RST# */ + IOMUX_PADS(PAD_GPIO_0__GPIO1_IO00 | DIO_PAD_CFG), + /* M2_OFF# */ + IOMUX_PADS(PAD_SD2_DAT0__GPIO1_IO15 | DIO_PAD_CFG), + /* M2_WDIS# */ + IOMUX_PADS(PAD_SD2_DAT1__GPIO1_IO14 | DIO_PAD_CFG), + /* M2_RST# */ + IOMUX_PADS(PAD_SD2_DAT2__GPIO1_IO13 | DIO_PAD_CFG), + /* RS232_EN# */ + IOMUX_PADS(PAD_SD4_DAT3__GPIO2_IO11 | DIO_PAD_CFG), +}; + +static iomux_v3_cfg_t const gw5905_gpio_pads[] = { + /* EMMY_PDN# */ + IOMUX_PADS(PAD_NANDF_D3__GPIO2_IO03 | DIO_PAD_CFG), + /* MX6_LOCLED# */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* MIPI_RST */ + IOMUX_PADS(PAD_SD2_DAT0__GPIO1_IO15 | DIO_PAD_CFG), + /* MIPI_PWDN */ + IOMUX_PADS(PAD_SD2_DAT1__GPIO1_IO14 | DIO_PAD_CFG), + /* USBEHCI_SEL */ + IOMUX_PADS(PAD_GPIO_7__GPIO1_IO07 | DIO_PAD_CFG), + /* PCI_RST# */ + IOMUX_PADS(PAD_GPIO_16__GPIO7_IO11 | DIO_PAD_CFG), + /* LVDS_BKLEN # */ + IOMUX_PADS(PAD_GPIO_17__GPIO7_IO12 | DIO_PAD_CFG), + /* PCIESKT_WDIS# */ + IOMUX_PADS(PAD_GPIO_18__GPIO7_IO13 | DIO_PAD_CFG), + /* SPK_SHDN# */ + IOMUX_PADS(PAD_GPIO_19__GPIO4_IO05 | DIO_PAD_CFG), + /* LOCLED# */ + IOMUX_PADS(PAD_NANDF_CS1__GPIO6_IO14 | DIO_PAD_CFG), + /* FLASH LED1 */ + IOMUX_PADS(PAD_DISP0_DAT11__GPIO5_IO05 | DIO_PAD_CFG), + /* FLASH LED2 */ + IOMUX_PADS(PAD_DISP0_DAT12__GPIO5_IO06 | DIO_PAD_CFG), + /* DECT_RST# */ + IOMUX_PADS(PAD_DISP0_DAT20__GPIO5_IO14 | DIO_PAD_CFG), + /* USBH1_PEN (EHCI) */ + IOMUX_PADS(PAD_EIM_D31__GPIO3_IO31 | DIO_PAD_CFG), + /* LVDS_PWM */ + IOMUX_PADS(PAD_GPIO_9__GPIO1_IO09 | DIO_PAD_CFG), + /* CODEC_RST */ + IOMUX_PADS(PAD_DISP0_DAT23__GPIO5_IO17 | DIO_PAD_CFG), + /* GYRO_CONTROL/DATA_EN */ + IOMUX_PADS(PAD_CSI0_DAT8__GPIO5_IO26 | DIO_PAD_CFG), + /* TOUCH_RST */ + IOMUX_PADS(PAD_KEY_COL1__GPIO4_IO08 | DIO_PAD_CFG), + /* TOUCH_IRQ */ + IOMUX_PADS(PAD_KEY_COL0__GPIO4_IO06 | DIO_PAD_CFG), +}; + +/* Digital I/O */ +struct dio_cfg gw51xx_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw52xx_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw53xx_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw54xx_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw551x_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw552x_dio[] = { + { + { 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 + }, + { + {IOMUX_PADS(PAD_CSI0_PIXCLK__GPIO5_IO18) }, + IMX_GPIO_NR(5, 18), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_CSI0_DATA_EN__GPIO5_IO20) }, + IMX_GPIO_NR(5, 20), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_CSI0_VSYNC__GPIO5_IO21) }, + IMX_GPIO_NR(5, 21), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_CSI0_DAT4__GPIO5_IO22) }, + IMX_GPIO_NR(5, 22), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_CSI0_DAT5__GPIO5_IO23) }, + IMX_GPIO_NR(5, 23), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_CSI0_DAT7__GPIO5_IO25) }, + IMX_GPIO_NR(5, 25), + { 0, 0 }, + 0 + }, +}; + +struct dio_cfg gw553x_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw560x_dio[] = { + { + { 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 + }, +}; + +struct dio_cfg gw5901_dio[] = { + { + { IOMUX_PADS(PAD_DISP0_DAT20__GPIO5_IO14) }, + IMX_GPIO_NR(5, 14), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_DISP0_DAT21__GPIO5_IO15) }, + IMX_GPIO_NR(5, 15), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_DISP0_DAT22__GPIO5_IO16) }, + IMX_GPIO_NR(5, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_DISP0_DAT23__GPIO5_IO17) }, + IMX_GPIO_NR(5, 17), + { 0, 0 }, + 0 + }, +}; + +struct dio_cfg gw5902_dio[] = { + { + { IOMUX_PADS(PAD_DISP0_DAT20__GPIO5_IO14) }, + IMX_GPIO_NR(5, 14), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_DISP0_DAT21__GPIO5_IO15) }, + IMX_GPIO_NR(5, 15), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_DISP0_DAT22__GPIO5_IO16) }, + IMX_GPIO_NR(5, 16), + { 0, 0 }, + 0 + }, + { + { IOMUX_PADS(PAD_DISP0_DAT23__GPIO5_IO17) }, + IMX_GPIO_NR(5, 17), + { 0, 0 }, + 0 + }, +}; + +struct dio_cfg gw5903_dio[] = { +}; + +struct dio_cfg gw5904_dio[] = { + { + { 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 + }, + { + {IOMUX_PADS(PAD_NANDF_D0__GPIO2_IO00) }, + IMX_GPIO_NR(2, 0), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D1__GPIO2_IO01) }, + IMX_GPIO_NR(2, 1), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D2__GPIO2_IO02) }, + IMX_GPIO_NR(2, 2), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D3__GPIO2_IO03) }, + IMX_GPIO_NR(2, 3), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D4__GPIO2_IO04) }, + IMX_GPIO_NR(2, 4), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D5__GPIO2_IO05) }, + IMX_GPIO_NR(2, 5), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D6__GPIO2_IO06) }, + IMX_GPIO_NR(2, 6), + { 0, 0 }, + 0 + }, + { + {IOMUX_PADS(PAD_NANDF_D7__GPIO2_IO07) }, + IMX_GPIO_NR(2, 7), + { 0, 0 }, + 0 + }, +}; + +struct dio_cfg gw5906_dio[] = { + { + { 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 + }, +}; + +/* + * 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 = gw54xx_dio, + .dio_num = ARRAY_SIZE(gw54xx_dio), + .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), + .mmc_cd = IMX_GPIO_NR(7, 0), + }, + + /* GW51xx */ + { + .gpio_pads = gw51xx_gpio_pads, + .num_pads = ARRAY_SIZE(gw51xx_gpio_pads)/2, + .dio_cfg = gw51xx_dio, + .dio_num = ARRAY_SIZE(gw51xx_dio), + .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), + .nand = true, + }, + + /* GW52xx */ + { + .gpio_pads = gw52xx_gpio_pads, + .num_pads = ARRAY_SIZE(gw52xx_gpio_pads)/2, + .dio_cfg = gw52xx_dio, + .dio_num = ARRAY_SIZE(gw52xx_dio), + .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, + .rs232_en = GP_RS232_EN, + .vsel_pin = IMX_GPIO_NR(6, 14), + .mmc_cd = IMX_GPIO_NR(7, 0), + .nand = true, + }, + + /* GW53xx */ + { + .gpio_pads = gw53xx_gpio_pads, + .num_pads = ARRAY_SIZE(gw53xx_gpio_pads)/2, + .dio_cfg = gw53xx_dio, + .dio_num = ARRAY_SIZE(gw53xx_dio), + .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, + .rs232_en = GP_RS232_EN, + .vsel_pin = IMX_GPIO_NR(6, 14), + .mmc_cd = IMX_GPIO_NR(7, 0), + .nand = true, + }, + + /* GW54xx */ + { + .gpio_pads = gw54xx_gpio_pads, + .num_pads = ARRAY_SIZE(gw54xx_gpio_pads)/2, + .dio_cfg = gw54xx_dio, + .dio_num = ARRAY_SIZE(gw54xx_dio), + .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, + .rs232_en = GP_RS232_EN, + .vsel_pin = IMX_GPIO_NR(6, 14), + .mmc_cd = IMX_GPIO_NR(7, 0), + .nand = true, + }, + + /* GW551x */ + { + .gpio_pads = gw551x_gpio_pads, + .num_pads = ARRAY_SIZE(gw551x_gpio_pads)/2, + .dio_cfg = gw551x_dio, + .dio_num = ARRAY_SIZE(gw551x_dio), + .leds = { + IMX_GPIO_NR(4, 7), + }, + .pcie_rst = IMX_GPIO_NR(1, 0), + .wdis = IMX_GPIO_NR(7, 12), + .nand = true, + }, + + /* GW552x */ + { + .gpio_pads = gw552x_gpio_pads, + .num_pads = ARRAY_SIZE(gw552x_gpio_pads)/2, + .dio_cfg = gw552x_dio, + .dio_num = ARRAY_SIZE(gw552x_dio), + .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, + .nand = true, + }, + + /* GW553x */ + { + .gpio_pads = gw553x_gpio_pads, + .num_pads = ARRAY_SIZE(gw553x_gpio_pads)/2, + .dio_cfg = gw553x_dio, + .dio_num = ARRAY_SIZE(gw553x_dio), + .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), + .vsel_pin = IMX_GPIO_NR(6, 14), + .mmc_cd = IMX_GPIO_NR(7, 0), + .nand = true, + }, + + /* GW560x */ + { + .gpio_pads = gw560x_gpio_pads, + .num_pads = ARRAY_SIZE(gw560x_gpio_pads)/2, + .dio_cfg = gw560x_dio, + .dio_num = ARRAY_SIZE(gw560x_dio), + .leds = { + IMX_GPIO_NR(4, 6), + IMX_GPIO_NR(4, 7), + IMX_GPIO_NR(4, 15), + }, + .pcie_rst = IMX_GPIO_NR(4, 31), + .mezz_pwren = IMX_GPIO_NR(2, 19), + .mezz_irq = IMX_GPIO_NR(2, 18), + .rs232_en = GP_RS232_EN, + .vidin_en = IMX_GPIO_NR(3, 31), + .wdis = IMX_GPIO_NR(7, 12), + .mmc_cd = IMX_GPIO_NR(7, 0), + }, + + /* GW5901 */ + { + .gpio_pads = gw5901_gpio_pads, + .num_pads = ARRAY_SIZE(gw5901_gpio_pads)/2, + .dio_cfg = gw5901_dio, + .leds = { + IMX_GPIO_NR(4, 15), + }, + .pcie_rst = IMX_GPIO_NR(1, 29), + .nand = true, + }, + + /* GW5902 */ + { + .gpio_pads = gw5902_gpio_pads, + .num_pads = ARRAY_SIZE(gw5902_gpio_pads)/2, + .dio_cfg = gw5902_dio, + .leds = { + IMX_GPIO_NR(4, 15), + }, + .pcie_rst = IMX_GPIO_NR(1, 0), + .rs232_en = GP_RS232_EN, + .nand = true, + }, + + /* GW5903 */ + { + .gpio_pads = gw5903_gpio_pads, + .num_pads = ARRAY_SIZE(gw5903_gpio_pads)/2, + .dio_cfg = gw5903_dio, + .dio_num = ARRAY_SIZE(gw5903_dio), + .leds = { + IMX_GPIO_NR(6, 14), + }, + .mmc_cd = IMX_GPIO_NR(6, 11), + }, + + /* GW5904 */ + { + .gpio_pads = gw5904_gpio_pads, + .num_pads = ARRAY_SIZE(gw5904_gpio_pads)/2, + .dio_cfg = gw5904_dio, + .dio_num = ARRAY_SIZE(gw5904_dio), + .leds = { + IMX_GPIO_NR(4, 6), + IMX_GPIO_NR(4, 7), + IMX_GPIO_NR(4, 15), + }, + .pcie_rst = IMX_GPIO_NR(1, 0), + .mezz_pwren = IMX_GPIO_NR(2, 19), + .mezz_irq = IMX_GPIO_NR(2, 18), + }, + + /* GW5905 */ + { + .gpio_pads = gw5905_gpio_pads, + .num_pads = ARRAY_SIZE(gw5905_gpio_pads)/2, + .leds = { + IMX_GPIO_NR(6, 14), + }, + .pcie_rst = IMX_GPIO_NR(7, 11), + .wdis = IMX_GPIO_NR(7, 13), + }, + + /* GW5906 */ + { + .gpio_pads = gw552x_gpio_pads, + .num_pads = ARRAY_SIZE(gw552x_gpio_pads)/2, + .dio_cfg = gw5906_dio, + .dio_num = ARRAY_SIZE(gw5906_dio), + .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, + .nand = true, + }, + + /* GW5907 */ + { + .gpio_pads = gw51xx_gpio_pads, + .num_pads = ARRAY_SIZE(gw51xx_gpio_pads)/2, + .dio_cfg = gw51xx_dio, + .dio_num = ARRAY_SIZE(gw51xx_dio), + .leds = { + IMX_GPIO_NR(4, 6), + IMX_GPIO_NR(4, 10), + }, + .pcie_rst = IMX_GPIO_NR(1, 0), + .wdis = IMX_GPIO_NR(7, 12), + .nand = true, + }, + + /* GW5908 */ + { + .gpio_pads = gw53xx_gpio_pads, + .num_pads = ARRAY_SIZE(gw53xx_gpio_pads)/2, + .dio_cfg = gw53xx_dio, + .dio_num = ARRAY_SIZE(gw53xx_dio), + .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, + .rs232_en = GP_RS232_EN, + }, + + /* GW5909 */ + { + .gpio_pads = gw5904_gpio_pads, + .num_pads = ARRAY_SIZE(gw5904_gpio_pads)/2, + .dio_cfg = gw5904_dio, + .dio_num = ARRAY_SIZE(gw5904_dio), + .leds = { + IMX_GPIO_NR(4, 6), + IMX_GPIO_NR(4, 7), + IMX_GPIO_NR(4, 15), + }, + .pcie_rst = IMX_GPIO_NR(1, 0), + .mezz_pwren = IMX_GPIO_NR(2, 19), + .mezz_irq = IMX_GPIO_NR(2, 18), + }, +}; + +#define SETUP_GPIO_OUTPUT(gpio, name, level) \ + gpio_request(gpio, name); \ + gpio_direction_output(gpio, level); +#define SETUP_GPIO_INPUT(gpio, name) \ + gpio_request(gpio, name); \ + gpio_direction_input(gpio); +void setup_iomux_gpio(int board, struct ventana_board_info *info) +{ + int i; + + if (board >= GW_UNKNOWN) + return; + + /* board specific iomux */ + imx_iomux_v3_setup_multiple_pads(gpio_cfg[board].gpio_pads, + gpio_cfg[board].num_pads); + + /* RS232_EN# */ + if (gpio_cfg[board].rs232_en) { + gpio_request(gpio_cfg[board].rs232_en, "rs232_en#"); + gpio_direction_output(gpio_cfg[board].rs232_en, 0); + } + + /* 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 */ + if (gpio_cfg[board].vsel_pin) { + gpio_request(gpio_cfg[board].vsel_pin, "sd3_vselect"); + gpio_direction_input(gpio_cfg[board].vsel_pin); + gpio_cfg[board].usd_vsel = !gpio_get_value(gpio_cfg[board].vsel_pin); + } + + /* microSD CD */ + if (gpio_cfg[board].mmc_cd) { + gpio_request(gpio_cfg[board].mmc_cd, "sd_cd"); + gpio_direction_input(gpio_cfg[board].mmc_cd); + } + + /* Anything else board specific */ + switch(board) { + case GW560x: + gpio_request(IMX_GPIO_NR(4, 26), "12p0_en"); + gpio_direction_output(IMX_GPIO_NR(4, 26), 1); + break; + case GW5901: + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(1, 2), "can_stby", 0); + break; + case GW5902: + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(1, 2), "can1_stby", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(7, 3), "can2_stby", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(7, 12), "5P0V_EN", 1); + break; + case GW5903: + gpio_request(IMX_GPIO_NR(3, 31) , "usbh1-ehci_pwr"); + gpio_direction_output(IMX_GPIO_NR(3, 31), 1); + gpio_request(IMX_GPIO_NR(4, 15) , "usbh2-otg_pwr"); + gpio_direction_output(IMX_GPIO_NR(4, 15), 1); + gpio_request(IMX_GPIO_NR(4, 7) , "usbdpc_pwr"); + gpio_direction_output(IMX_GPIO_NR(4, 15), 1); + gpio_request(IMX_GPIO_NR(1, 25) , "rgmii_en"); + gpio_direction_output(IMX_GPIO_NR(1, 25), 1); + gpio_request(IMX_GPIO_NR(4, 6) , "touch_irq#"); + gpio_direction_input(IMX_GPIO_NR(4, 6)); + gpio_request(IMX_GPIO_NR(4, 8) , "touch_rst"); + gpio_direction_output(IMX_GPIO_NR(4, 8), 1); + gpio_request(IMX_GPIO_NR(1, 7) , "bklt_12ven"); + gpio_direction_output(IMX_GPIO_NR(1, 7), 1); + break; + case GW5909: + case GW5904: + gpio_request(IMX_GPIO_NR(4, 23), "rs485_en"); + gpio_direction_output(IMX_GPIO_NR(4, 23), 0); + gpio_request(IMX_GPIO_NR(5, 11), "skt1_wdis#"); + gpio_direction_output(IMX_GPIO_NR(5, 11), 1); + gpio_request(IMX_GPIO_NR(5, 12), "skt1_rst#"); + gpio_direction_output(IMX_GPIO_NR(5, 12), 1); + gpio_request(IMX_GPIO_NR(5, 13), "skt2_wdis#"); + gpio_direction_output(IMX_GPIO_NR(5, 13), 1); + gpio_request(IMX_GPIO_NR(1, 15), "m2_off#"); + gpio_direction_output(IMX_GPIO_NR(1, 15), 1); + gpio_request(IMX_GPIO_NR(1, 14), "m2_wdis#"); + gpio_direction_output(IMX_GPIO_NR(1, 14), 1); + gpio_request(IMX_GPIO_NR(1, 13), "m2_rst#"); + gpio_direction_output(IMX_GPIO_NR(1, 13), 1); + break; + case GW5905: + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(1, 7), "usb_pcisel", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(1, 9), "lvds_cabc", 1); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(1, 14), "mipi_pdwn", 1); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(1, 15), "mipi_rst#", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(2, 3), "emmy_pdwn#", 1); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(4, 5), "spk_shdn#", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(4, 8), "touch_rst", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(4, 6), "touch_irq", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(5, 5), "flash_en1", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(5, 6), "flash_en2", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(5, 14), "dect_rst#", 1); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(5, 17), "codec_rst#", 0); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(5, 26), "imu_den", 1); + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(7, 12), "lvds_cabc", 0); + mdelay(100); + /* + * gauruntee touch controller comes out of reset with INT + * low for address + */ + SETUP_GPIO_OUTPUT(IMX_GPIO_NR(4, 8), "touch_rst", 1); + break; + } +} + +/* 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(env_get("quiet"), NULL, 10); + + if (board >= GW_UNKNOWN) + return; + + /* RS232_EN# */ + if (gpio_cfg[board].rs232_en) { + gpio_direction_output(gpio_cfg[board].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].dio_num; 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")); + } + if (gpio_cfg[board].rs232_en) { + printf("RS232: %s\n", (hwconfig("rs232")) ? + "enabled" : "disabled"); + } + } +} + +/* setup board specific PMIC */ +void setup_pmic(void) +{ + struct pmic *p; + struct ventana_board_info ventana_info; + int board = read_eeprom(CONFIG_I2C_GSC, &ventana_info); + const int i2c_pmic = 1; + u32 reg; + + i2c_set_bus_num(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(i2c_pmic); + p = pmic_get("PFUZE100"); + if (p && !pmic_probe(p)) { + pmic_reg_read(p, PFUZE100_DEVICEID, ®); + printf("PMIC: PFUZE100 ID=0x%02x\n", reg); + + /* Set VGEN1 to 1.5V and enable */ + pmic_reg_read(p, PFUZE100_VGEN1VOL, ®); + 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 &= ~(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(i2c_pmic); + p = pmic_get("LTC3676_PMIC"); + if (!p || pmic_probe(p)) + return; + 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. + */ + switch (board) { + case GW560x: + /* 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); + break; + case GW5903: + /* 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); + + /* mask PGOOD during SW4 transition */ + pmic_reg_write(p, LTC3676_DVB4B, + 0x1f | LTC3676_PGOOD_MASK); + /* set SW4 (VDD_SOC) */ + pmic_reg_write(p, LTC3676_DVB4A, 0x1f); + break; + case GW5905: + /* mask PGOOD during SW1 transition */ + pmic_reg_write(p, LTC3676_DVB1B, + 0x1f | LTC3676_PGOOD_MASK); + /* set SW1 (VDD_ARM) */ + 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_SOC) */ + pmic_reg_write(p, LTC3676_DVB3A, 0x1f); + break; + default: + /* 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); + } + } +} + +#ifdef CONFIG_FSL_ESDHC_IMX +static struct fsl_esdhc_cfg usdhc_cfg[2]; + +int board_mmc_init(struct bd_info *bis) +{ + struct ventana_board_info ventana_info; + int board_type = read_eeprom(CONFIG_I2C_GSC, &ventana_info); + int ret; + + switch (board_type) { + case GW52xx: + case GW53xx: + case GW54xx: + case GW553x: + /* usdhc3: 4bit microSD */ + SETUP_IOMUX_PADS(usdhc3_pads); + usdhc_cfg[0].esdhc_base = USDHC3_BASE_ADDR; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + usdhc_cfg[0].max_bus_width = 4; + return fsl_esdhc_initialize(bis, &usdhc_cfg[0]); + case GW560x: + /* usdhc2: 8-bit eMMC */ + SETUP_IOMUX_PADS(gw560x_emmc_sd2_pads); + usdhc_cfg[0].esdhc_base = USDHC2_BASE_ADDR; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); + usdhc_cfg[0].max_bus_width = 8; + ret = fsl_esdhc_initialize(bis, &usdhc_cfg[0]); + if (ret) + return ret; + /* usdhc3: 4-bit microSD */ + SETUP_IOMUX_PADS(usdhc3_pads); + usdhc_cfg[1].esdhc_base = USDHC3_BASE_ADDR; + usdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + usdhc_cfg[1].max_bus_width = 4; + return fsl_esdhc_initialize(bis, &usdhc_cfg[1]); + case GW5903: + /* usdhc3: 8-bit eMMC */ + SETUP_IOMUX_PADS(gw5904_emmc_pads); + usdhc_cfg[0].esdhc_base = USDHC3_BASE_ADDR; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + usdhc_cfg[0].max_bus_width = 8; + ret = fsl_esdhc_initialize(bis, &usdhc_cfg[0]); + if (ret) + return ret; + /* usdhc2: 4-bit microSD */ + SETUP_IOMUX_PADS(gw5904_mmc_pads); + usdhc_cfg[1].esdhc_base = USDHC2_BASE_ADDR; + usdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); + usdhc_cfg[1].max_bus_width = 4; + return fsl_esdhc_initialize(bis, &usdhc_cfg[1]); + case GW5904: + case GW5905: + case GW5909: + /* usdhc3: 8bit eMMC */ + SETUP_IOMUX_PADS(gw5904_emmc_pads); + usdhc_cfg[0].esdhc_base = USDHC3_BASE_ADDR; + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); + usdhc_cfg[0].max_bus_width = 8; + return fsl_esdhc_initialize(bis, &usdhc_cfg[0]); + default: + /* doesn't have MMC */ + return -1; + } +} + +int board_mmc_getcd(struct mmc *mmc) +{ + struct ventana_board_info ventana_info; + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + int board = read_eeprom(CONFIG_I2C_GSC, &ventana_info); + int gpio = gpio_cfg[board].mmc_cd; + + /* Card Detect */ + switch (board) { + case GW560x: + /* emmc is always present */ + if (cfg->esdhc_base == USDHC2_BASE_ADDR) + return 1; + break; + case GW5903: + case GW5904: + case GW5905: + case GW5909: + /* emmc is always present */ + if (cfg->esdhc_base == USDHC3_BASE_ADDR) + return 1; + break; + } + + if (gpio) { + debug("%s: gpio%d=%d\n", __func__, gpio, gpio_get_value(gpio)); + return !gpio_get_value(gpio); + } + + return -1; +} + +#endif /* CONFIG_FSL_ESDHC_IMX */ diff --git a/roms/u-boot/board/gateworks/gw_ventana/common.h b/roms/u-boot/board/gateworks/gw_ventana/common.h new file mode 100644 index 000000000..813f7d9f5 --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/common.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2013 Gateworks Corporation + * + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#ifndef _GWVENTANA_COMMON_H_ +#define _GWVENTANA_COMMON_H_ + +#include "ventana_eeprom.h" + +/* GPIO's common to all baseboards */ +#define GP_RS232_EN IMX_GPIO_NR(2, 11) +#define GP_MSATA_SEL IMX_GPIO_NR(2, 8) + +#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 an optional set 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; + int dio_num; + /* 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; + int rs232_en; + int vsel_pin; + int mmc_cd; + /* various features */ + bool usd_vsel; + bool nand; +}; + +extern struct ventana gpio_cfg[GW_UNKNOWN]; + +/* configure i2c iomux */ +void setup_ventana_i2c(int); +/* 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_ */ diff --git a/roms/u-boot/board/gateworks/gw_ventana/eeprom.c b/roms/u-boot/board/gateworks/gw_ventana/eeprom.c new file mode 100644 index 000000000..b9862c7df --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/eeprom.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Gateworks Corporation + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <command.h> +#include <errno.h> +#include <hexdump.h> +#include <i2c.h> +#include <log.h> +#include <malloc.h> +#include <asm/bitops.h> +#include <linux/delay.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 */ + mdelay(10); + 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"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, + sizeof(*info)); + 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"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, + sizeof(*info)); + return GW_UNKNOWN; + } + + /* original GW5400-A prototype */ + baseboard = info->model[3]; + if (strncasecmp((const char *)info->model, "GW5400-A", 8) == 0) + baseboard = '0'; + + type = GW_UNKNOWN; + 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; + } + break; + case '6': + if (info->model[4] == '0') + type = GW560x; + break; + case '9': + if (info->model[4] == '0' && info->model[5] == '1') + type = GW5901; + else if (info->model[4] == '0' && info->model[5] == '2') + type = GW5902; + else if (info->model[4] == '0' && info->model[5] == '3') + type = GW5903; + else if (info->model[4] == '0' && info->model[5] == '4') + type = GW5904; + else if (info->model[4] == '0' && info->model[5] == '5') + type = GW5905; + else if (info->model[4] == '0' && info->model[5] == '6') + type = GW5906; + else if (info->model[4] == '0' && info->model[5] == '7') + type = GW5907; + else if (info->model[4] == '0' && info->model[5] == '8') + type = GW5908; + else if (info->model[4] == '0' && info->model[5] == '9') + type = GW5909; + break; + default: + printf("EEPROM: Unknown model in EEPROM: %s\n", info->model); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, + sizeof(*info)); + 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 */ } +}; + +#if defined(CONFIG_CMD_EECONFIG) && !defined(CONFIG_SPL_BUILD) +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; + +static int do_econfig(struct cmd_tbl *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 */ diff --git a/roms/u-boot/board/gateworks/gw_ventana/gsc.c b/roms/u-boot/board/gateworks/gw_ventana/gsc.c new file mode 100644 index 000000000..ffed6b5fc --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/gsc.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Gateworks Corporation + * + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <command.h> +#include <log.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <common.h> +#include <i2c.h> +#include <linux/ctype.h> + +#include <asm/arch/sys_proto.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 (size == 2 && 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; + case '6': /* GW560x */ + read_hwmon("VDD_IO4", GSC_HWMON_VDD_IO4, 3); + read_hwmon("VDD_GPS", GSC_HWMON_VDD_IO3, 3); + break; + case '9': /* GW590x */ + read_hwmon("AMONBMON", GSC_HWMON_VDD_IO3, 3); + read_hwmon("BAT_VOLT", GSC_HWMON_VDD_EXT, 3); + read_hwmon("BAT_TEMP", GSC_HWMON_VDD_IO4, 2); + } + 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, ®, 1)) { + reg |= (1 << GSC_SC_CTRL1_WDDIS); + if (!gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, ®, 1)) + return 0; + } + puts("Error: could not disable GSC Watchdog\n"); + return 1; +} + +/* determine BOM revision from model */ +int get_bom_rev(const char *str) +{ + int rev_bom = 0; + int i; + + for (i = strlen(str) - 1; i > 0; i--) { + if (str[i] == '-') + break; + if (str[i] >= '1' && str[i] <= '9') { + rev_bom = str[i] - '0'; + break; + } + } + return rev_bom; +} + +/* determine PCB revision from model */ +char get_pcb_rev(const char *str) +{ + char rev_pcb = 'A'; + int i; + + for (i = strlen(str) - 1; i > 0; i--) { + if (str[i] == '-') + break; + if (str[i] >= 'A') { + rev_pcb = str[i]; + break; + } + } + return rev_pcb; +} + +/* + * get dt name based on model and detail level: + */ +const char *gsc_get_dtb_name(int level, char *buf, int sz) +{ + const char *model = (const char *)ventana_info.model; + const char *pre = is_mx6dq() ? "imx6q-" : "imx6dl-"; + int modelno, rev_pcb, rev_bom; + + /* a few board models are dt equivalents to other models */ + if (strncasecmp(model, "gw5906", 6) == 0) + model = "gw552x-d"; + else if (strncasecmp(model, "gw5908", 6) == 0) + model = "gw53xx-f"; + else if (strncasecmp(model, "gw5905", 6) == 0) + model = "gw5904-a"; + + modelno = ((model[2] - '0') * 1000) + + ((model[3] - '0') * 100) + + ((model[4] - '0') * 10) + + (model[5] - '0'); + rev_pcb = tolower(get_pcb_rev(model)); + rev_bom = get_bom_rev(model); + + /* compare model/rev/bom in order of most specific to least */ + snprintf(buf, sz, "%s%04d", pre, modelno); + switch (level) { + case 0: /* full model first (ie gw5400-a1) */ + if (rev_bom) { + snprintf(buf, sz, "%sgw%04d-%c%d", pre, modelno, rev_pcb, rev_bom); + break; + } + fallthrough; + case 1: /* don't care about bom rev (ie gw5400-a) */ + snprintf(buf, sz, "%sgw%04d-%c", pre, modelno, rev_pcb); + break; + case 2: /* don't care about the pcb rev (ie gw5400) */ + snprintf(buf, sz, "%sgw%04d", pre, modelno); + break; + case 3: /* look for generic model (ie gw540x) */ + snprintf(buf, sz, "%sgw%03dx", pre, modelno / 10); + break; + case 4: /* look for more generic model (ie gw54xx) */ + snprintf(buf, sz, "%sgw%02dxx", pre, modelno / 100); + break; + default: /* give up */ + return NULL; + } + + return buf; +} + +#if defined(CONFIG_CMD_GSC) && !defined(CONFIG_SPL_BUILD) +static int do_gsc_sleep(struct cmd_tbl *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, ®, 1)) + goto error; + reg = (secs >> 16) & 0xff; + if (gsc_i2c_write(GSC_SC_ADDR, 8, 1, ®, 1)) + goto error; + reg = (secs >> 8) & 0xff; + if (gsc_i2c_write(GSC_SC_ADDR, 7, 1, ®, 1)) + goto error; + reg = secs & 0xff; + if (gsc_i2c_write(GSC_SC_ADDR, 6, 1, ®, 1)) + goto error; + if (gsc_i2c_read(GSC_SC_ADDR, GSC_SC_CTRL1, 1, ®, 1)) + goto error; + reg |= (1 << 2); + if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, ®, 1)) + goto error; + reg &= ~(1 << 2); + reg |= 0x3; + if (gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, 1, ®, 1)) + goto error; + + return CMD_RET_SUCCESS; + +error: + printf("i2c error\n"); + return CMD_RET_FAILURE; +} + +static int do_gsc_wd(struct cmd_tbl *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, ®, 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, ®, 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, ®, 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, ®, 1)) + return CMD_RET_FAILURE; + printf("GSC Watchdog disabled\n"); + } else { + return CMD_RET_USAGE; + } + return CMD_RET_SUCCESS; +} + +static int do_gsc(struct cmd_tbl *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 */ diff --git a/roms/u-boot/board/gateworks/gw_ventana/gsc.h b/roms/u-boot/board/gateworks/gw_ventana/gsc.h new file mode 100644 index 000000000..29d375b3a --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/gsc.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2013 Gateworks Corporation + * + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#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_SOC = 0x11, + GSC_HWMON_VDD_HIGH = 0x14, + GSC_HWMON_VDD_DDR = 0x17, + GSC_HWMON_VDD_EXT = 0x1a, + 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); +const char *gsc_get_dtb_name(int level, char *buf, int sz); +#endif + diff --git a/roms/u-boot/board/gateworks/gw_ventana/gw_ventana.c b/roms/u-boot/board/gateworks/gw_ventana/gw_ventana.c new file mode 100644 index 000000000..1ed9c1a39 --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/gw_ventana.c @@ -0,0 +1,1223 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 Gateworks Corporation + * + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <init.h> +#include <log.h> +#include <net.h> +#include <asm/arch/clock.h> +#include <asm/arch/crm_regs.h> +#include <asm/arch/iomux.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/mxc_hdmi.h> +#include <asm/arch/sys_proto.h> +#include <asm/global_data.h> +#include <asm/gpio.h> +#include <asm/mach-imx/boot_mode.h> +#include <asm/mach-imx/sata.h> +#include <asm/mach-imx/video.h> +#include <asm/io.h> +#include <asm/setup.h> +#include <dm.h> +#include <env.h> +#include <hwconfig.h> +#include <i2c.h> +#include <fdt_support.h> +#include <jffs2/load_kernel.h> +#include <linux/ctype.h> +#include <miiphy.h> +#include <mtd_node.h> +#include <pci.h> +#include <linux/delay.h> +#include <linux/libfdt.h> +#include <power/pmic.h> +#include <power/ltc3676_pmic.h> +#include <power/pfuze100_pmic.h> +#include <fdt_support.h> +#include <jffs2/load_kernel.h> + +#include "gsc.h" +#include "common.h" + +DECLARE_GLOBAL_DATA_PTR; + + +/* + * EEPROM board info struct populated by read_eeprom so that we only have to + * read it once. + */ +struct ventana_board_info ventana_info; +static int board_type; + +#ifdef CONFIG_USB_EHCI_MX6 +/* toggle USB_HUB_RST# for boards that have it; it is not defined in dt */ +int board_ehci_hcd_init(int port) +{ + int gpio; + + /* USB HUB is always on P1 */ + if (port == 0) + return 0; + + /* Reset USB HUB */ + switch (board_type) { + case GW53xx: + case GW552x: + case GW5906: + gpio = (IMX_GPIO_NR(1, 9)); + break; + case GW54proto: + case GW54xx: + gpio = (IMX_GPIO_NR(1, 16)); + break; + default: + return 0; + } + + /* request and toggle hub rst */ + gpio_request(gpio, "usb_hub_rst#"); + gpio_direction_output(gpio, 0); + mdelay(2); + gpio_set_value(gpio, 1); + + return 0; +} +#endif /* CONFIG_USB_EHCI_MX6 */ + +/* configure eth0 PHY board-specific LED behavior */ +int board_phy_config(struct phy_device *phydev) +{ + unsigned short val; + + /* Marvel 88E1510 */ + if (phydev->phy_id == 0x1410dd1) { + /* + * Page 3, Register 16: LED[2:0] Function Control Register + * 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); + } + + /* TI DP83867 */ + else if (phydev->phy_id == 0x2000a231) { + /* configure register 0x170 for ref CLKOUT */ + phy_write(phydev, MDIO_DEVAD_NONE, 13, 0x001f); + phy_write(phydev, MDIO_DEVAD_NONE, 14, 0x0170); + phy_write(phydev, MDIO_DEVAD_NONE, 13, 0x401f); + val = phy_read(phydev, MDIO_DEVAD_NONE, 14); + val &= ~0x1f00; + val |= 0x0b00; /* chD tx clock*/ + phy_write(phydev, MDIO_DEVAD_NONE, 14, val); + } + + if (phydev->drv->config) + phydev->drv->config(phydev); + + return 0; +} + +#ifdef CONFIG_MV88E61XX_SWITCH +int mv88e61xx_hw_reset(struct phy_device *phydev) +{ + struct mii_dev *bus = phydev->bus; + + /* GPIO[0] output, CLK125 */ + debug("enabling RGMII_REFCLK\n"); + bus->write(bus, 0x1c /*MV_GLOBAL2*/, 0, + 0x1a /*MV_SCRATCH_MISC*/, + (1 << 15) | (0x62 /*MV_GPIO_DIR*/ << 8) | 0xfe); + bus->write(bus, 0x1c /*MV_GLOBAL2*/, 0, + 0x1a /*MV_SCRATCH_MISC*/, + (1 << 15) | (0x68 /*MV_GPIO01_CNTL*/ << 8) | 7); + + /* RGMII delay - Physical Control register bit[15:14] */ + debug("setting port%d RGMII rx/tx delay\n", CONFIG_MV88E61XX_CPU_PORT); + /* forced 1000mbps full-duplex link */ + bus->write(bus, 0x10 + CONFIG_MV88E61XX_CPU_PORT, 0, 1, 0xc0fe); + phydev->autoneg = AUTONEG_DISABLE; + phydev->speed = SPEED_1000; + phydev->duplex = DUPLEX_FULL; + + /* LED configuration: 7:4-green (8=Activity) 3:0 amber (8=Link) */ + bus->write(bus, 0x10, 0, 0x16, 0x8088); + bus->write(bus, 0x11, 0, 0x16, 0x8088); + bus->write(bus, 0x12, 0, 0x16, 0x8088); + bus->write(bus, 0x13, 0, 0x16, 0x8088); + + return 0; +} +#endif // CONFIG_MV88E61XX_SWITCH + +#if defined(CONFIG_VIDEO_IPUV3) +static void enable_hdmi(struct display_info_t const *dev) +{ + imx_enable_hdmi_phy(); +} + +static int detect_i2c(struct display_info_t const *dev) +{ + return i2c_set_bus_num(dev->bus) == 0 && + i2c_probe(dev->addr) == 0; +} + +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]); + + /* Enable Backlight */ + gpio_request(IMX_GPIO_NR(1, 10), "bklt_gpio"); + gpio_direction_output(IMX_GPIO_NR(1, 10), 0); + gpio_request(IMX_GPIO_NR(1, 18), "bklt_en"); + SETUP_IOMUX_PAD(PAD_SD1_CMD__GPIO1_IO18 | DIO_PAD_CFG); + gpio_direction_output(IMX_GPIO_NR(1, 18), 1); +} + +struct display_info_t const displays[] = {{ + /* HDMI Output */ + .bus = -1, + .addr = 0, + .pixfmt = IPU_PIX_FMT_RGB24, + .detect = detect_hdmi, + .enable = 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 +} }, { + /* Freescale MXC-LVDS1: HannStar HSD100PXN1-A00 w/ egalx_ts cont */ + .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 +} }, { + /* DLC700JMG-T-4 */ + .bus = 2, + .addr = 0x38, + .detect = NULL, + .enable = enable_lvds, + .pixfmt = IPU_PIX_FMT_LVDS666, + .mode = { + .name = "DLC700JMGT4", + .refresh = 60, + .xres = 1024, /* 1024x600active pixels */ + .yres = 600, + .pixclock = 15385, /* 64MHz */ + .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 +} }, { + /* DLC800FIG-T-3 */ + .bus = 2, + .addr = 0x14, + .detect = NULL, + .enable = enable_lvds, + .pixfmt = IPU_PIX_FMT_LVDS666, + .mode = { + .name = "DLC800FIGT3", + .refresh = 60, + .xres = 1024, /* 1024x768 active pixels */ + .yres = 768, + .pixclock = 15385, /* 64MHz */ + .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 +} }, { + .bus = 2, + .addr = 0x5d, + .detect = detect_i2c, + .enable = enable_lvds, + .pixfmt = IPU_PIX_FMT_LVDS666, + .mode = { + .name = "Z101WX01", + .refresh = 60, + .xres = 1280, + .yres = 800, + .pixclock = 15385, /* 64MHz */ + .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 + } +}, +}; +size_t display_count = ARRAY_SIZE(displays); + +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 = __raw_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]); + + /* LVDS Backlight GPIO on LVDS connector - output low */ + SETUP_IOMUX_PAD(PAD_SD2_CLK__GPIO1_IO10 | DIO_PAD_CFG); + gpio_direction_output(IMX_GPIO_NR(1, 10), 0); +} +#endif /* CONFIG_VIDEO_IPUV3 */ + +/* setup board specific PMIC */ +int power_init_board(void) +{ + setup_pmic(); + return 0; +} + +int imx6_pcie_toggle_reset(void) +{ + if (board_type < GW_UNKNOWN) { + uint pin = gpio_cfg[board_type].pcie_rst; + gpio_request(pin, "pci_rst#"); + gpio_direction_output(pin, 0); + mdelay(50); + gpio_direction_output(pin, 1); + } + return 0; +} + +/* + * Most Ventana boards have a PLX PEX860x PCIe switch onboard and use its + * GPIO's as PERST# signals for its downstream ports - configure the GPIO's + * properly and assert reset for 100ms. + */ +#define MAX_PCI_DEVS 32 +struct pci_dev { + pci_dev_t devfn; + struct udevice *dev; + unsigned short vendor; + unsigned short device; + unsigned short class; + unsigned short busno; /* subbordinate busno */ + struct pci_dev *ppar; +}; +struct pci_dev pci_devs[MAX_PCI_DEVS]; +int pci_devno; +int pci_bridgeno; + +void board_pci_fixup_dev(struct udevice *bus, struct udevice *udev) +{ + struct pci_child_plat *pdata = dev_get_parent_plat(udev); + struct pci_dev *pdev = &pci_devs[pci_devno++]; + unsigned short vendor = pdata->vendor; + unsigned short device = pdata->device; + unsigned int class = pdata->class; + pci_dev_t dev = dm_pci_get_bdf(udev); + int i; + + debug("%s: %02d:%02d.%02d: %04x:%04x\n", __func__, + PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev), vendor, device); + + /* store array of devs for later use in device-tree fixup */ + pdev->dev = udev; + pdev->devfn = dev; + pdev->vendor = vendor; + pdev->device = device; + pdev->class = class; + pdev->ppar = NULL; + if (class == PCI_CLASS_BRIDGE_PCI) + pdev->busno = ++pci_bridgeno; + else + pdev->busno = 0; + + /* fixup RC - it should be 00:00.0 not 00:01.0 */ + if (PCI_BUS(dev) == 0) + pdev->devfn = 0; + + /* find dev's parent */ + for (i = 0; i < pci_devno; i++) { + if (pci_devs[i].busno == PCI_BUS(pdev->devfn)) { + pdev->ppar = &pci_devs[i]; + break; + } + } + + /* assert downstream PERST# */ + if (vendor == PCI_VENDOR_ID_PLX && + (device & 0xfff0) == 0x8600 && + PCI_DEV(dev) == 0 && PCI_FUNC(dev) == 0) { + ulong val; + debug("configuring PLX 860X downstream PERST#\n"); + pci_bus_read_config(bus, dev, 0x62c, &val, PCI_SIZE_32); + val |= 0xaaa8; /* GPIO1-7 outputs */ + pci_bus_write_config(bus, dev, 0x62c, val, PCI_SIZE_32); + + pci_bus_read_config(bus, dev, 0x644, &val, PCI_SIZE_32); + val |= 0xfe; /* GPIO1-7 output high */ + pci_bus_write_config(bus, dev, 0x644, val, PCI_SIZE_32); + + mdelay(100); + } +} + +#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 = env_get("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 + +/* + * Board Support + */ + +int board_early_init_f(void) +{ +#if defined(CONFIG_VIDEO_IPUV3) + setup_display(); +#endif + return 0; +} + +int dram_init(void) +{ + gd->ram_size = imx_ddr_size(); + return 0; +} + +int board_init(void) +{ + struct iomuxc *const iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; + + clrsetbits_le32(&iomuxc_regs->gpr[1], + IOMUXC_GPR1_OTG_ID_MASK, + IOMUXC_GPR1_OTG_ID_GPIO1); + + /* address of linux boot parameters */ + gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; + + /* read Gateworks EEPROM into global struct (used later) */ + setup_ventana_i2c(0); + board_type = read_eeprom(CONFIG_I2C_GSC, &ventana_info); + + setup_ventana_i2c(1); + setup_ventana_i2c(2); + + setup_iomux_gpio(board_type, &ventana_info); + + return 0; +} + +int board_fit_config_name_match(const char *name) +{ + static char init; + const char *dtb; + char buf[32]; + int i = 0; + + do { + dtb = gsc_get_dtb_name(i++, buf, sizeof(buf)); + if (dtb && !strcmp(dtb, name)) { + if (!init++) + printf("DTB: %s\n", name); + return 0; + } + } while (dtb); + + return -1; +} + +#if defined(CONFIG_DISPLAY_BOARDINFO_LATE) +/* + * called during late init (after relocation and after board_init()) + * by virtue of CONFIG_DISPLAY_BOARDINFO_LATE as we needed i2c initialized and + * EEPROM read. + */ +int checkboard(void) +{ + struct ventana_board_info *info = &ventana_info; + unsigned char buf[4]; + const char *p; + int quiet; /* Quiet or minimal output mode */ + + quiet = 0; + p = env_get("quiet"); + if (p) + quiet = simple_strtol(p, NULL, 10); + else + env_set("quiet", "0"); + + puts("\nGateworks 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 { + puts("Invalid EEPROM - board will not function fully\n"); + } + if (quiet) + return 0; + + /* Display GSC firmware revision/CRC/status */ + gsc_info(0); + + /* Display RTC */ + if (!gsc_i2c_read(GSC_RTC_ADDR, 0x00, 1, buf, 4)) { + printf("RTC: %d\n", + buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24); + } + + return 0; +} +#endif + +#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: 64pages per block, 3 row addr cycles, 2 copies of FCB/DBBT */ + { "nand", MAKE_CFGVAL(0x80, 0x02, 0x00, 0x00) }, + { "emmc2", MAKE_CFGVAL(0x60, 0x48, 0x00, 0x00) }, /* GW5600 */ + { "emmc3", MAKE_CFGVAL(0x60, 0x50, 0x00, 0x00) }, /* GW5903/4/5 */ + { NULL, 0 }, +}; +#endif + +/* late init */ +int misc_init_r(void) +{ + struct ventana_board_info *info = &ventana_info; + char buf[256]; + int i; + + /* set env vars based on EEPROM data */ + if (ventana_info.model[0]) { + char str[16], fdt[36]; + char *p; + const char *cputype = ""; + + /* + * FDT name will be prefixed with CPU type. Three versions + * will be created each increasingly generic and bootloader + * env scripts will try loading each from most specific to + * least. + */ + if (is_cpu_type(MXC_CPU_MX6Q) || + is_cpu_type(MXC_CPU_MX6D)) + cputype = "imx6q"; + else if (is_cpu_type(MXC_CPU_MX6DL) || + is_cpu_type(MXC_CPU_MX6SOLO)) + cputype = "imx6dl"; + env_set("soctype", cputype); + if (8 << (ventana_info.nand_flash_size-1) >= 2048) + env_set("flash_layout", "large"); + else + env_set("flash_layout", "normal"); + memset(str, 0, sizeof(str)); + for (i = 0; i < (sizeof(str)-1) && info->model[i]; i++) + str[i] = tolower(info->model[i]); + env_set("model", str); + if (!env_get("fdt_file")) { + sprintf(fdt, "%s-%s.dtb", cputype, str); + env_set("fdt_file", fdt); + } + p = strchr(str, '-'); + if (p) { + *p++ = 0; + + env_set("model_base", str); + sprintf(fdt, "%s-%s.dtb", cputype, str); + env_set("fdt_file1", fdt); + if (board_type != GW551x && + board_type != GW552x && + board_type != GW553x && + board_type != GW560x) + str[4] = 'x'; + str[5] = 'x'; + str[6] = 0; + sprintf(fdt, "%s-%s.dtb", cputype, str); + env_set("fdt_file2", fdt); + } + + /* initialize env from EEPROM */ + if (test_bit(EECONFIG_ETH0, info->config) && + !env_get("ethaddr")) { + eth_env_set_enetaddr("ethaddr", info->mac0); + } + if (test_bit(EECONFIG_ETH1, info->config) && + !env_get("eth1addr")) { + eth_env_set_enetaddr("eth1addr", info->mac1); + } + + /* board serial-number */ + sprintf(str, "%6d", info->serial); + env_set("serial#", str); + + /* memory MB */ + sprintf(str, "%d", (int) (gd->ram_size >> 20)); + env_set("mem_mb", str); + } + + /* Set a non-initialized hwconfig based on board configuration */ + if (!strcmp(env_get("hwconfig"), "_UNKNOWN_")) { + buf[0] = 0; + if (gpio_cfg[board_type].rs232_en) + strcat(buf, "rs232;"); + for (i = 0; i < gpio_cfg[board_type].dio_num; i++) { + char buf1[32]; + sprintf(buf1, "dio%d:mode=gpio;", i); + if (strlen(buf) + strlen(buf1) < sizeof(buf)) + strcat(buf, buf1); + } + env_set("hwconfig", buf); + } + + /* setup baseboard specific GPIO based on board and env */ + setup_board_gpio(board_type, info); + +#ifdef CONFIG_CMD_BMODE + add_board_boot_modes(board_boot_modes); +#endif + + /* disable boot watchdog */ + gsc_boot_wd_disable(); + + return 0; +} + +#ifdef CONFIG_OF_BOARD_SETUP + +static int ft_sethdmiinfmt(void *blob, char *mode) +{ + int off; + + if (!mode) + return -EINVAL; + + off = fdt_node_offset_by_compatible(blob, -1, "nxp,tda1997x"); + if (off < 0) + return off; + + if (0 == strcasecmp(mode, "yuv422bt656")) { + u8 cfg[] = { 0x00, 0x00, 0x00, 0x82, 0x81, 0x00, + 0x00, 0x00, 0x00 }; + mode = "422_ccir"; + fdt_setprop(blob, off, "vidout_fmt", mode, strlen(mode) + 1); + fdt_setprop_u32(blob, off, "vidout_trc", 1); + fdt_setprop_u32(blob, off, "vidout_blc", 1); + fdt_setprop(blob, off, "vidout_portcfg", cfg, sizeof(cfg)); + printf(" set HDMI input mode to %s\n", mode); + } else if (0 == strcasecmp(mode, "yuv422smp")) { + u8 cfg[] = { 0x00, 0x00, 0x00, 0x88, 0x87, 0x00, + 0x82, 0x81, 0x00 }; + mode = "422_smp"; + fdt_setprop(blob, off, "vidout_fmt", mode, strlen(mode) + 1); + fdt_setprop_u32(blob, off, "vidout_trc", 0); + fdt_setprop_u32(blob, off, "vidout_blc", 0); + fdt_setprop(blob, off, "vidout_portcfg", cfg, sizeof(cfg)); + printf(" set HDMI input mode to %s\n", mode); + } else { + return -EINVAL; + } + + return 0; +} + +#if defined(CONFIG_CMD_PCI) +#define PCI_ID(x) ( \ + (PCI_BUS(x->devfn)<<16)| \ + (PCI_DEV(x->devfn)<<11)| \ + (PCI_FUNC(x->devfn)<<8) \ + ) +int fdt_add_pci_node(void *blob, int par, struct pci_dev *dev) +{ + uint32_t reg[5]; + char node[32]; + int np; + + sprintf(node, "pcie@%d,%d,%d", PCI_BUS(dev->devfn), + PCI_DEV(dev->devfn), PCI_FUNC(dev->devfn)); + + np = fdt_subnode_offset(blob, par, node); + if (np >= 0) + return np; + np = fdt_add_subnode(blob, par, node); + if (np < 0) { + printf(" %s failed: no space\n", __func__); + return np; + } + + memset(reg, 0, sizeof(reg)); + reg[0] = cpu_to_fdt32(PCI_ID(dev)); + fdt_setprop(blob, np, "reg", reg, sizeof(reg)); + + return np; +} + +/* build a path of nested PCI devs for all bridges passed through */ +int fdt_add_pci_path(void *blob, struct pci_dev *dev) +{ + struct pci_dev *bridges[MAX_PCI_DEVS]; + int k, np; + + /* build list of parents */ + np = fdt_node_offset_by_compatible(blob, -1, "fsl,imx6q-pcie"); + if (np < 0) + return np; + + k = 0; + while (dev) { + bridges[k++] = dev; + dev = dev->ppar; + }; + + /* now add them the to DT in reverse order */ + while (k--) { + np = fdt_add_pci_node(blob, np, bridges[k]); + if (np < 0) + break; + } + + return np; +} + +/* + * The GW16082 has a hardware errata errata such that it's + * INTA/B/C/D are mis-mapped to its four slots (slot12-15). Because + * of this normal PCI interrupt swizzling will not work so we will + * provide an irq-map via device-tree. + */ +int fdt_fixup_gw16082(void *blob, int np, struct pci_dev *dev) +{ + int len; + int host; + uint32_t imap_new[8*4*4]; + const uint32_t *imap; + uint32_t irq[4]; + uint32_t reg[4]; + int i; + + /* build irq-map based on host controllers map */ + host = fdt_node_offset_by_compatible(blob, -1, "fsl,imx6q-pcie"); + if (host < 0) { + printf(" %s failed: missing host\n", __func__); + return host; + } + + /* use interrupt data from root complex's node */ + imap = fdt_getprop(blob, host, "interrupt-map", &len); + if (!imap || len != 128) { + printf(" %s failed: invalid interrupt-map\n", + __func__); + return -FDT_ERR_NOTFOUND; + } + + /* obtain irq's of host controller in pin order */ + for (i = 0; i < 4; i++) + irq[(fdt32_to_cpu(imap[(i*8)+3])-1)%4] = imap[(i*8)+6]; + + /* + * determine number of swizzles necessary: + * For each bridge we pass through we need to swizzle + * the number of the slot we are on. + */ + struct pci_dev *d; + int b; + b = 0; + d = dev->ppar; + while(d && d->ppar) { + b += PCI_DEV(d->devfn); + d = d->ppar; + } + + /* create new irq mappings for slots12-15 + * <skt> <idsel> <slot> <skt-inta> <skt-intb> + * J3 AD28 12 INTD INTA + * J4 AD29 13 INTC INTD + * J5 AD30 14 INTB INTC + * J2 AD31 15 INTA INTB + */ + for (i = 0; i < 4; i++) { + /* addr matches bus:dev:func */ + u32 addr = dev->busno << 16 | (12+i) << 11; + + /* default cells from root complex */ + memcpy(&imap_new[i*32], imap, 128); + /* first cell is PCI device address (BDF) */ + imap_new[(i*32)+(0*8)+0] = cpu_to_fdt32(addr); + imap_new[(i*32)+(1*8)+0] = cpu_to_fdt32(addr); + imap_new[(i*32)+(2*8)+0] = cpu_to_fdt32(addr); + imap_new[(i*32)+(3*8)+0] = cpu_to_fdt32(addr); + /* third cell is pin */ + imap_new[(i*32)+(0*8)+3] = cpu_to_fdt32(1); + imap_new[(i*32)+(1*8)+3] = cpu_to_fdt32(2); + imap_new[(i*32)+(2*8)+3] = cpu_to_fdt32(3); + imap_new[(i*32)+(3*8)+3] = cpu_to_fdt32(4); + /* sixth cell is relative interrupt */ + imap_new[(i*32)+(0*8)+6] = irq[(15-(12+i)+b+0)%4]; + imap_new[(i*32)+(1*8)+6] = irq[(15-(12+i)+b+1)%4]; + imap_new[(i*32)+(2*8)+6] = irq[(15-(12+i)+b+2)%4]; + imap_new[(i*32)+(3*8)+6] = irq[(15-(12+i)+b+3)%4]; + } + fdt_setprop(blob, np, "interrupt-map", imap_new, + sizeof(imap_new)); + reg[0] = cpu_to_fdt32(0xfff00); + reg[1] = 0; + reg[2] = 0; + reg[3] = cpu_to_fdt32(0x7); + fdt_setprop(blob, np, "interrupt-map-mask", reg, sizeof(reg)); + fdt_setprop_cell(blob, np, "#interrupt-cells", 1); + fdt_setprop_string(blob, np, "device_type", "pci"); + fdt_setprop_cell(blob, np, "#address-cells", 3); + fdt_setprop_cell(blob, np, "#size-cells", 2); + printf(" Added custom interrupt-map for GW16082\n"); + + return 0; +} + +/* The sky2 GigE MAC obtains it's MAC addr from device-tree by default */ +int fdt_fixup_sky2(void *blob, int np, struct pci_dev *dev) +{ + char *tmp, *end; + char mac[16]; + unsigned char mac_addr[6]; + int j; + + sprintf(mac, "eth1addr"); + tmp = env_get(mac); + if (tmp) { + for (j = 0; j < 6; j++) { + mac_addr[j] = tmp ? + simple_strtoul(tmp, &end,16) : 0; + if (tmp) + tmp = (*end) ? end+1 : end; + } + fdt_setprop(blob, np, "local-mac-address", mac_addr, + sizeof(mac_addr)); + printf(" Added mac addr for eth1\n"); + return 0; + } + + return -1; +} + +/* + * PCI DT nodes must be nested therefore if we need to apply a DT fixup + * we will walk the PCI bus and add bridge nodes up to the device receiving + * the fixup. + */ +void ft_board_pci_fixup(void *blob, struct bd_info *bd) +{ + int i, np; + struct pci_dev *dev; + + for (i = 0; i < pci_devno; i++) { + dev = &pci_devs[i]; + + /* + * The GW16082 consists of a TI XIO2001 PCIe-to-PCI bridge and + * an EEPROM at i2c1-0x50. + */ + if ((dev->vendor == PCI_VENDOR_ID_TI) && + (dev->device == 0x8240) && + (i2c_set_bus_num(1) == 0) && + (i2c_probe(0x50) == 0)) + { + np = fdt_add_pci_path(blob, dev); + if (np > 0) + fdt_fixup_gw16082(blob, np, dev); + } + + /* ethernet1 mac address */ + else if ((dev->vendor == PCI_VENDOR_ID_MARVELL) && + (dev->device == 0x4380)) + { + np = fdt_add_pci_path(blob, dev); + if (np > 0) + fdt_fixup_sky2(blob, np, dev); + } + } +} +#endif /* if defined(CONFIG_CMD_PCI) */ + +void ft_board_wdog_fixup(void *blob, phys_addr_t addr) +{ + int off = fdt_node_offset_by_compat_reg(blob, "fsl,imx6q-wdt", addr); + + if (off) { + fdt_delprop(blob, off, "ext-reset-output"); + fdt_delprop(blob, off, "fsl,ext-reset-output"); + } +} + +/* + * called prior to booting kernel or by 'fdt boardsetup' command + * + * unless 'fdt_noauto' env var is set we will update the following in the DTB: + * - mtd partitions based on mtdparts/mtdids env + * - system-serial (board serial num from EEPROM) + * - board (full model from EEPROM) + * - peripherals removed from DTB if not loaded on board (per EEPROM config) + */ +#define WDOG1_ADDR 0x20bc000 +#define WDOG2_ADDR 0x20c0000 +#define GPIO3_ADDR 0x20a4000 +#define USDHC3_ADDR 0x2198000 +#define PWM0_ADDR 0x2080000 +int ft_board_setup(void *blob, struct bd_info *bd) +{ + struct ventana_board_info *info = &ventana_info; + struct ventana_eeprom_config *cfg; + static const 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 = env_get("model"); + const char *display = env_get("display"); + int i; + char rev = 0; + + /* determine board revision */ + for (i = sizeof(ventana_info.model) - 1; i > 0; i--) { + if (ventana_info.model[i] >= 'A') { + rev = ventana_info.model[i]; + break; + } + } + + if (env_get("fdt_noauto")) { + puts(" Skiping ft_board_setup (fdt_noauto defined)\n"); + return 0; + } + + if (test_bit(EECONFIG_NAND, info->config)) { + /* Update partition nodes using info from mtdparts env var */ + puts(" Updating MTD partitions...\n"); + fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); + } + + /* Update display timings from display env var */ + if (display) { + if (fdt_fixup_display(blob, fdt_get_alias(blob, "lvds0"), + display) >= 0) + printf(" Set display timings for %s...\n", display); + } + + printf(" Adjusting FDT per EEPROM for %s...\n", model); + + /* board serial number */ + fdt_setprop(blob, 0, "system-serial", env_get("serial#"), + strlen(env_get("serial#")) + 1); + + /* board (model contains model from device-tree) */ + fdt_setprop(blob, 0, "board", info->model, + strlen((const char *)info->model) + 1); + + /* set desired digital video capture format */ + ft_sethdmiinfmt(blob, env_get("hdmiinfmt")); + + /* + * Board model specific fixups + */ + switch (board_type) { + case GW51xx: + /* + * disable wdog node for GW51xx-A/B to work around + * errata causing wdog timer to be unreliable. + */ + if (rev >= 'A' && rev < 'C') { + i = fdt_node_offset_by_compat_reg(blob, "fsl,imx6q-wdt", + WDOG1_ADDR); + if (i) + fdt_status_disabled(blob, i); + } + + /* GW51xx-E adds WDOG1_B external reset */ + if (rev < 'E') + ft_board_wdog_fixup(blob, WDOG1_ADDR); + break; + + case GW52xx: + /* GW522x Uses GPIO3_IO23 instead of GPIO1_IO29 */ + if (info->model[4] == '2') { + u32 handle = 0; + u32 *range = NULL; + + i = fdt_node_offset_by_compatible(blob, -1, + "fsl,imx6q-pcie"); + if (i) + range = (u32 *)fdt_getprop(blob, i, + "reset-gpio", NULL); + + if (range) { + i = fdt_node_offset_by_compat_reg(blob, + "fsl,imx6q-gpio", GPIO3_ADDR); + if (i) + handle = fdt_get_phandle(blob, i); + if (handle) { + range[0] = cpu_to_fdt32(handle); + range[1] = cpu_to_fdt32(23); + } + } + + /* these have broken usd_vsel */ + if (strstr((const char *)info->model, "SP318-B") || + strstr((const char *)info->model, "SP331-B")) + gpio_cfg[board_type].usd_vsel = 0; + + /* GW522x-B adds WDOG1_B external reset */ + if (rev < 'B') + ft_board_wdog_fixup(blob, WDOG1_ADDR); + } + + /* GW520x-E adds WDOG1_B external reset */ + else if (info->model[4] == '0' && rev < 'E') + ft_board_wdog_fixup(blob, WDOG1_ADDR); + break; + + case GW53xx: + /* GW53xx-E adds WDOG1_B external reset */ + if (rev < 'E') + ft_board_wdog_fixup(blob, WDOG1_ADDR); + break; + + case GW54xx: + /* + * disable serial2 node for GW54xx for compatibility with older + * 3.10.x kernel that improperly had this node enabled in the DT + */ + fdt_set_status_by_alias(blob, "serial2", FDT_STATUS_DISABLED, + 0); + + /* GW54xx-E adds WDOG2_B external reset */ + if (rev < 'E') + ft_board_wdog_fixup(blob, WDOG2_ADDR); + break; + + case GW551x: + /* + * isolate CSI0_DATA_EN for GW551x-A to work around errata + * causing non functional digital video in (it is not hooked up) + */ + if (rev == 'A') { + u32 *range = NULL; + int len; + const u32 *handle = NULL; + + i = fdt_node_offset_by_compatible(blob, -1, + "fsl,imx-tda1997x-video"); + if (i) + handle = fdt_getprop(blob, i, "pinctrl-0", + NULL); + if (handle) + i = fdt_node_offset_by_phandle(blob, + fdt32_to_cpu(*handle)); + if (i) + range = (u32 *)fdt_getprop(blob, i, "fsl,pins", + &len); + if (range) { + len /= sizeof(u32); + for (i = 0; i < len; i += 6) { + u32 mux_reg = fdt32_to_cpu(range[i+0]); + u32 conf_reg = fdt32_to_cpu(range[i+1]); + /* mux PAD_CSI0_DATA_EN to GPIO */ + if (is_cpu_type(MXC_CPU_MX6Q) && + mux_reg == 0x260 && + conf_reg == 0x630) + range[i+3] = cpu_to_fdt32(0x5); + else if (!is_cpu_type(MXC_CPU_MX6Q) && + mux_reg == 0x08c && + conf_reg == 0x3a0) + range[i+3] = cpu_to_fdt32(0x5); + } + fdt_setprop_inplace(blob, i, "fsl,pins", range, + len); + } + + /* set BT656 video format */ + ft_sethdmiinfmt(blob, "yuv422bt656"); + } + + /* GW551x-C adds WDOG1_B external reset */ + if (rev < 'C') + ft_board_wdog_fixup(blob, WDOG1_ADDR); + break; + case GW5901: + case GW5902: + /* GW5901/GW5901 revB adds WDOG1_B as an external reset */ + if (rev < 'B') + ft_board_wdog_fixup(blob, WDOG1_ADDR); + break; + } + + /* Configure DIO */ + for (i = 0; i < gpio_cfg[board_type].dio_num; i++) { + struct dio_cfg *cfg = &gpio_cfg[board_type].dio_cfg[i]; + char arg[10]; + + sprintf(arg, "dio%d", i); + if (!hwconfig(arg)) + continue; + if (hwconfig_subarg_cmp(arg, "mode", "pwm") && cfg->pwm_param) + { + phys_addr_t addr; + int off; + + printf(" Enabling pwm%d for DIO%d\n", + cfg->pwm_param, i); + addr = PWM0_ADDR + (0x4000 * (cfg->pwm_param - 1)); + off = fdt_node_offset_by_compat_reg(blob, + "fsl,imx6q-pwm", + addr); + if (off) + fdt_status_okay(blob, off); + } + } + + /* remove no-1-8-v if UHS-I support is present */ + if (gpio_cfg[board_type].usd_vsel) { + debug("Enabling UHS-I support\n"); + i = fdt_node_offset_by_compat_reg(blob, "fsl,imx6q-usdhc", + USDHC3_ADDR); + if (i) + fdt_delprop(blob, i, "no-1-8-v"); + } + +#if defined(CONFIG_CMD_PCI) + if (!env_get("nopcifixup")) + ft_board_pci_fixup(blob, bd); +#endif + + /* + * Peripheral Config: + * remove nodes by alias path if EEPROM config tells us the + * peripheral is not loaded on the board. + */ + if (env_get("fdt_noconfig")) { + puts(" Skiping periperhal config (fdt_noconfig defined)\n"); + return 0; + } + cfg = econfig; + while (cfg->name) { + if (!test_bit(cfg->bit, info->config)) { + fdt_del_node_and_alias(blob, cfg->dtalias ? + cfg->dtalias : cfg->name); + } + cfg++; + } + + return 0; +} +#endif /* CONFIG_OF_BOARD_SETUP */ diff --git a/roms/u-boot/board/gateworks/gw_ventana/gw_ventana_spl.c b/roms/u-boot/board/gateworks/gw_ventana/gw_ventana_spl.c new file mode 100644 index 000000000..a4f64395a --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/gw_ventana_spl.c @@ -0,0 +1,787 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Gateworks Corporation + * Author: Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <env.h> +#include <hang.h> +#include <init.h> +#include <log.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/mach-imx/boot_mode.h> +#include <asm/mach-imx/iomux-v3.h> +#include <asm/mach-imx/mxc_i2c.h> +#include <env.h> +#include <i2c.h> +#include <spl.h> + +#include "gsc.h" +#include "common.h" + +#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, +}; + +/* TODO: update with calibrated values */ +static struct mx6_mmdc_calibration mx6dq_64x64_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, +}; + +/* TODO: update with calibrated values */ +static struct mx6_mmdc_calibration mx6sdl_64x64_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_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 mx6sdl_256x64_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x0048004A, + .p0_mpwldectrl1 = 0x003F004A, + .p1_mpwldectrl0 = 0x001E0028, + .p1_mpwldectrl1 = 0x002C0043, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x02250219, + .p0_mpdgctrl1 = 0x01790202, + .p1_mpdgctrl0 = 0x02080208, + .p1_mpdgctrl1 = 0x016C0175, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x4A4C4D4C, + .p1_mprddlctl = 0x494C4A48, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x403F3437, + .p1_mpwrdlctl = 0x383A3930, +}; + +static struct mx6_mmdc_calibration mx6sdl_256x64x2_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x001F003F, + .p0_mpwldectrl1 = 0x001F001F, + .p1_mpwldectrl0 = 0x001F004E, + .p1_mpwldectrl1 = 0x0059001F, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x42220225, + .p0_mpdgctrl1 = 0x0213021F, + .p1_mpdgctrl0 = 0x022C0242, + .p1_mpdgctrl1 = 0x022C0244, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x474A4C4A, + .p1_mprddlctl = 0x48494C45, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x3F3F3F36, + .p1_mpwrdlctl = 0x3F36363F, +}; + +static struct mx6_mmdc_calibration mx6sdl_128x64x2_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x001F003F, + .p0_mpwldectrl1 = 0x001F001F, + .p1_mpwldectrl0 = 0x001F004E, + .p1_mpwldectrl1 = 0x0059001F, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x42220225, + .p0_mpdgctrl1 = 0x0213021F, + .p1_mpdgctrl0 = 0x022C0242, + .p1_mpdgctrl1 = 0x022C0244, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x474A4C4A, + .p1_mprddlctl = 0x48494C45, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x3F3F3F36, + .p1_mpwrdlctl = 0x3F36363F, +}; + +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 struct mx6_mmdc_calibration mx6dq_512x64_mmdc_calib = { + /* write leveling calibration determine */ + .p0_mpwldectrl0 = 0x00230020, + .p0_mpwldectrl1 = 0x002F002A, + .p1_mpwldectrl0 = 0x001D0027, + .p1_mpwldectrl1 = 0x00100023, + /* Read DQS Gating calibration */ + .p0_mpdgctrl0 = 0x03250339, + .p0_mpdgctrl1 = 0x031C0316, + .p1_mpdgctrl0 = 0x03210331, + .p1_mpdgctrl1 = 0x031C025A, + /* Read Calibration: DQS delay relative to DQ read access */ + .p0_mprddlctl = 0x40373C40, + .p1_mprddlctl = 0x3A373646, + /* Write Calibration: DQ/DM delay relative to DQS write access */ + .p0_mpwrdlctl = 0x2E353933, + .p1_mpwrdlctl = 0x3C2F3F35, +}; + +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, + .refsel = 1, /* Refresh cycles at 32KHz */ + .refr = 7, /* 8 refresh commands per refresh cycle */ + }; + + /* + * 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 == 16 && size_mb == 1024) { + mem = &mt41k512m16ha_125; + if (is_cpu_type(MXC_CPU_MX6Q)) + calib = &mx6dq_512x32_mmdc_calib; + debug("8gB 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"); + if (is_cpu_type(MXC_CPU_MX6Q)) + calib = &mx6dq_64x64_mmdc_calib; + else + calib = &mx6sdl_64x64_mmdc_calib; + } 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) { + switch(board_model) { + case GW5905: + /* 8xMT41K128M16 (2GiB) fly-by mirrored 2-chipsels */ + mem = &mt41k128m16jt_125; + debug("2gB density - 2 chipsel\n"); + if (!is_cpu_type(MXC_CPU_MX6Q)) { + calib = &mx6sdl_128x64x2_mmdc_calib; + sysinfo.ncs = 2; + sysinfo.cs_density = 10; /* CS0_END=39 */ + sysinfo.cs1_mirror = 1; /* mirror enabled */ + } + break; + default: + mem = &mt41k256m16ha_125; + if (is_cpu_type(MXC_CPU_MX6Q)) + calib = &mx6dq_256x64_mmdc_calib; + else + calib = &mx6sdl_256x64_mmdc_calib; + debug("4gB density\n"); + break; + } + } else if (width == 64 && size_mb == 4096) { + switch(board_model) { + case GW5903: + /* 8xMT41K256M16 (4GiB) fly-by mirrored 2-chipsels */ + mem = &mt41k256m16ha_125; + debug("4gB density - 2 chipsel\n"); + if (!is_cpu_type(MXC_CPU_MX6Q)) { + calib = &mx6sdl_256x64x2_mmdc_calib; + sysinfo.ncs = 2; + sysinfo.cs_density = 18; /* CS0_END=71 */ + sysinfo.cs1_mirror = 1; /* mirror enabled */ + } + break; + default: + mem = &mt41k512m16ha_125; + if (is_cpu_type(MXC_CPU_MX6Q)) + calib = &mx6dq_512x64_mmdc_calib; + debug("8gB density\n"); + break; + } + } + + 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); +} + +/* + * 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 uart/i2c */ + setup_iomux_uart(); + setup_ventana_i2c(0); + setup_ventana_i2c(1); + + /* 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); +} + +void board_boot_order(u32 *spl_boot_list) +{ + spl_boot_list[0] = spl_boot_device(); + switch (spl_boot_list[0]) { + case BOOT_DEVICE_NAND: + spl_boot_list[1] = BOOT_DEVICE_MMC1; + spl_boot_list[2] = BOOT_DEVICE_UART; + break; + case BOOT_DEVICE_MMC1: + spl_boot_list[1] = BOOT_DEVICE_UART; + break; + } +} + +/* 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) +{ + u32 boot_device; + int board_type; + + /* determine boot device from SRC_SBMR1 (BOOT_CFG[4:1]) or SRC_GPR9 */ + boot_device = spl_boot_device(); + + /* read eeprom again now that we have gd */ + board_type = read_eeprom(CONFIG_I2C_GSC, &ventana_info); + if (board_type == GW_UNKNOWN) + hang(); + + 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_load(); + debug("boot_os=%s\n", env_get("boot_os")); + if (env_get_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 diff --git a/roms/u-boot/board/gateworks/gw_ventana/ventana_eeprom.h b/roms/u-boot/board/gateworks/gw_ventana/ventana_eeprom.h new file mode 100644 index 000000000..4fa085b32 --- /dev/null +++ b/roms/u-boot/board/gateworks/gw_ventana/ventana_eeprom.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2013 Gateworks Corporation + */ + +#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, + GW560x, + GW5901, + GW5902, + GW5903, + GW5904, + GW5905, + GW5906, + GW5907, + GW5908, + GW5909, + 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 |