summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/mxs.rst119
-rw-r--r--Documentation/boards/mxs/KaRo-TX28.rst19
-rw-r--r--arch/arm/boards/imx233-olinuxino/Makefile1
-rw-r--r--arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/boot/sd6
-rw-r--r--arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/init/automount-sd4
-rw-r--r--arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/network/eth0-discover (renamed from arch/arm/boards/imx233-olinuxino/env/network/eth0-discover)0
-rw-r--r--arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/boot.default1
-rw-r--r--arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/hostname1
-rw-r--r--arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/linux.bootargs.base1
-rw-r--r--arch/arm/boards/imx233-olinuxino/env/bin/boot32
-rw-r--r--arch/arm/boards/imx233-olinuxino/env/bin/init15
-rw-r--r--arch/arm/boards/imx233-olinuxino/env/config40
-rw-r--r--arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c73
-rw-r--r--arch/arm/boards/imx233-olinuxino/lowlevel.c170
-rw-r--r--arch/arm/boards/karo-tx28/env/config41
-rw-r--r--arch/arm/boards/karo-tx28/lowlevel.c58
-rw-r--r--arch/arm/configs/imx233-olinuxino_defconfig100
-rw-r--r--arch/arm/configs/tx28stk5_defconfig84
-rw-r--r--arch/arm/cpu/start.c11
-rw-r--r--arch/arm/cpu/uncompress.c9
-rw-r--r--arch/arm/include/asm/common.h26
-rw-r--r--arch/arm/include/asm/io.h57
-rw-r--r--arch/arm/mach-mxs/Kconfig11
-rw-r--r--arch/arm/mach-mxs/Makefile2
-rw-r--r--arch/arm/mach-mxs/clocksource-imx23.c2
-rw-r--r--arch/arm/mach-mxs/clocksource-imx28.c2
-rw-r--r--arch/arm/mach-mxs/include/mach/imx23-regs.h3
-rw-r--r--arch/arm/mach-mxs/include/mach/imx28-regs.h3
-rw-r--r--arch/arm/mach-mxs/include/mach/init.h33
-rw-r--r--arch/arm/mach-mxs/include/mach/iomux.h2
-rw-r--r--arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h208
-rw-r--r--arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h283
-rw-r--r--arch/arm/mach-mxs/include/mach/regs-common.h69
-rw-r--r--arch/arm/mach-mxs/include/mach/regs-lradc.h387
-rw-r--r--arch/arm/mach-mxs/include/mach/regs-power-mx28.h408
-rw-r--r--arch/arm/mach-mxs/include/mach/regs-rtc.h134
-rw-r--r--arch/arm/mach-mxs/lradc-init.c70
-rw-r--r--arch/arm/mach-mxs/mem-init.c371
-rw-r--r--arch/arm/mach-mxs/mxs23img.cfg6
-rw-r--r--arch/arm/mach-mxs/mxs28img.cfg8
-rw-r--r--arch/arm/mach-mxs/ocotp.c1
-rw-r--r--arch/arm/mach-mxs/power-init.c1272
-rw-r--r--arch/arm/mach-mxs/soc-imx23.c2
-rw-r--r--arch/arm/mach-mxs/soc-imx28.c2
-rw-r--r--arch/arm/mach-mxs/usb-imx23.c2
-rw-r--r--arch/arm/mach-mxs/usb-imx28.c2
-rw-r--r--common/Kconfig11
-rw-r--r--common/console_common.c2
-rw-r--r--common/memory.c8
-rw-r--r--common/misc.c22
-rw-r--r--drivers/clk/mxs/clk-imx23.c2
-rw-r--r--drivers/clk/mxs/clk-imx28.c2
-rw-r--r--drivers/mci/mxs.c1
-rw-r--r--drivers/serial/serial_auart.c1
-rw-r--r--drivers/serial/stm-serial.c1
-rw-r--r--drivers/spi/mxs_spi.c1
-rw-r--r--drivers/video/stm.c1
-rw-r--r--images/.gitignore2
-rw-r--r--images/Makefile3
-rw-r--r--images/Makefile.mxs43
-rw-r--r--include/malloc.h2
-rw-r--r--include/printk.h15
-rw-r--r--include/stdio.h20
-rw-r--r--lib/Makefile3
-rw-r--r--lib/strtox.c68
-rw-r--r--lib/vsprintf.c107
-rw-r--r--pbl/Makefile1
-rw-r--r--pbl/console.c32
-rw-r--r--pbl/string.c14
-rw-r--r--scripts/.gitignore2
-rw-r--r--scripts/Makefile5
-rw-r--r--scripts/mxs-usb-loader.c236
-rw-r--r--scripts/mxsboot.c641
-rw-r--r--scripts/mxsimage.c2561
74 files changed, 7576 insertions, 382 deletions
diff --git a/Documentation/boards/mxs.rst b/Documentation/boards/mxs.rst
new file mode 100644
index 0000000000..6c8bdb56fa
--- /dev/null
+++ b/Documentation/boards/mxs.rst
@@ -0,0 +1,119 @@
+Freescale i.MXs
+===============
+
+Freescale i.MXs or MXS are a SoC family which consists of the i.MX23
+and the i.MX28. These are quite different from the regular i.MX SoCs
+and thus are represented by its own architecture in both the Kernel
+and barebox.
+
+Bootlets
+--------
+
+Traditionally These SoCs need the Freescale bootlets source and the
+elf2sb2 binary to build a bootable image out of the barebox binary.
+Since the bootlets are board specific and the source code is only
+hardly customisable each vendor usually has his own slightly different
+version of the bootlets. Booting with the Freescale bootlets is not
+described here, refer to the bootlet sourcecode or your vendors
+documentation instead.
+
+U-Boot and barebox have a port of the bootlets integrated into their
+source. The barebox bootlet code is derived from the U-Boot bootlet
+code written by Marek Vasut.
+
+Currently only the Karo TX28 is supported by the barebox bootlets,
+but we recommend that this approach should be followed for new boards
+and existing boards should be ported over.
+
+Booting Freescale i.MXs
+-----------------------
+
+The Freescale MXS SoCs have a multi staged boot process which needs
+different images composed out of different binaries. The ROM executes
+a so called bootstream which contains multiple executables. The first
+one is executed in SRAM and the purpose of this binary is to setup
+the internal PMIC and the SDRAM. The second image is usually the
+bootloader itself. In case of barebox the bootstream is composed
+out of the self extracting barebox image (pblx) and the prepare
+stage for setting up the SDRAM.
+
+The bootstream image itself is useful for USB boot, but for booting from
+SD cards or NAND a BCB header has to be prepended to the image. In case
+of SD boot the image has the .mxssd file extension in barebox.
+
+Since the bootstream images are encrypted they are not suitable for
+2nd stage execution. For this purpose the 2nd stage images are generated.
+
+Booting from USB
+----------------
+
+barebox has the mxs-usb-loader tool (derived from the sbloader tool from
+the rockbox project). If the board is connected to the PC and started in
+USB Boot mode it should show up in lsusb::
+
+ Bus 001 Device 098: ID 15a2:004f Freescale Semiconductor, Inc. i.MX28 SystemOnChip in RecoveryMode
+
+The bootstream images can be directly booted with::
+
+ ./scripts/mxs-usb-loader 0 images/barebox-karo-tx28-bootstream.img
+
+You might require appropriate udev rules or sudo to gain the rights to
+access the USB device.
+
+Booting from SD cards
+---------------------
+
+The SD images are suitable for booting from SD cards. SD cards need a special
+partitioning which can be created with the following fdisk sequence (using
+/dev/sdg as example)::
+
+ fdisk /dev/sdg
+
+ Welcome to fdisk (util-linux 2.25.1).
+ Changes will remain in memory only, until you decide to write them.
+ Be careful before using the write command.
+
+
+ Command (m for help): o
+ Created a new DOS disklabel with disk identifier 0xd7e5d328.
+
+ Command (m for help): n
+ Partition type
+ p primary (0 primary, 0 extended, 4 free)
+ e extended (container for logical partitions)
+ Select (default p): p
+ Partition number (1-4, default 1): 1
+ First sector (2048-7829503, default 2048):
+ Last sector, +sectors or +size{K,M,G,T,P} (2048-7829503, default 7829503): +1M
+
+ Created a new partition 1 of type 'Linux' and of size 1 MiB.
+
+ Command (m for help): t
+ Selected partition 1
+ Hex code (type L to list all codes): 53
+ Changed type of partition 'Linux' to 'OnTrack DM6 Aux3'.
+
+ Command (m for help):
+
+ Command (m for help): w
+
+After writing the new partition table the image can be written directly to
+the partition::
+
+ cat images/barebox-karo-tx28-sd.img > /dev/sdg1
+
+** NOTE **
+
+The MXS SoCs require a special partition of type 0x53 (OnTrack DM6 Aux)
+which contains the BCB header. For some unknown reason the BCB header is
+inside a partition, but contains the sector number of the raw device from
+which the rest of the image is read from. With standard settings booting
+from SD card only works if the partition containing the bootloader starts
+at sector 2048 (the standard for fdisk). See the -p parameter to the
+mxsboot tool which changes this sector number in the image.
+
+Booting second stage
+--------------------
+
+The second stage images can be started with the barebox bootm command or
+just jumped into using the 'go' command.
diff --git a/Documentation/boards/mxs/KaRo-TX28.rst b/Documentation/boards/mxs/KaRo-TX28.rst
index 0fbd4dfd7d..0c5dc71ef3 100644
--- a/Documentation/boards/mxs/KaRo-TX28.rst
+++ b/Documentation/boards/mxs/KaRo-TX28.rst
@@ -34,20 +34,9 @@ Build the binary image::
**NOTE:** replace the armv5compiler with your ARM v5 cross compiler.
-**NOTE:** to use the result, you also need the following resources from Freescale:
+This produces the following images:
- * the 'bootlets' archive
- * the 'elftosb2' encryption tool
- * in the case you want to start barebox from an attached SD card
- the 'sdimage' tool from Freescale's 'uuc' archive.
+ * barebox-karo-tx28-bootstream.img - Use with the bcb command
+ * barebox-karo-tx28-sd.img - Use for SD cards
+ * barebox-karo-tx28-2nd.img - Use for 2nd stage booting (with bootm)
-Memory layout when barebox is running
--------------------------------------
-
- * 0x40000000 start of SDRAM
- * 0x40000100 start of kernel's boot parameters
-
- * below malloc area: stack area
- * below barebox: malloc area
-
- * 0x47000000 start of barebox
diff --git a/arch/arm/boards/imx233-olinuxino/Makefile b/arch/arm/boards/imx233-olinuxino/Makefile
index 644f7e5802..987b34394a 100644
--- a/arch/arm/boards/imx233-olinuxino/Makefile
+++ b/arch/arm/boards/imx233-olinuxino/Makefile
@@ -1,2 +1,3 @@
obj-y = imx23-olinuxino.o
lwl-y += lowlevel.o
+bbenv-y += defaultenv-imx233-olinuxino
diff --git a/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/boot/sd b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/boot/sd
new file mode 100644
index 0000000000..3ddfb9de20
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/boot/sd
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+global.bootm.image=/mnt/sd-boot/linuximage
+global.bootm.oftree=/mnt/sd-boot/imx23-olinuxino.dtb
+#global.bootm.initrd=<path to initrd>
+global.linux.bootargs.dyn.root="root=/dev/mmcblk0p3 rootfstype=ext4 rw rootwait"
diff --git a/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/init/automount-sd b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/init/automount-sd
new file mode 100644
index 0000000000..eb34c9b8ca
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/init/automount-sd
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+mkdir -p /mnt/sd-boot
+automount -d /mnt/sd-boot 'detect mci0 && [ -e /dev/disk0.1 ] && mount /dev/disk0.1 /mnt/sd-boot'
diff --git a/arch/arm/boards/imx233-olinuxino/env/network/eth0-discover b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/network/eth0-discover
index 76494fe6ea..76494fe6ea 100644
--- a/arch/arm/boards/imx233-olinuxino/env/network/eth0-discover
+++ b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/network/eth0-discover
diff --git a/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/boot.default b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/boot.default
new file mode 100644
index 0000000000..e1476cfc20
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/boot.default
@@ -0,0 +1 @@
+sd
diff --git a/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/hostname b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/hostname
new file mode 100644
index 0000000000..e5646edbc0
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/hostname
@@ -0,0 +1 @@
+olinuxino
diff --git a/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/linux.bootargs.base b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/linux.bootargs.base
new file mode 100644
index 0000000000..5b56cafbec
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/defaultenv-imx233-olinuxino/nv/linux.bootargs.base
@@ -0,0 +1 @@
+console=ttyAMA0,115200
diff --git a/arch/arm/boards/imx233-olinuxino/env/bin/boot b/arch/arm/boards/imx233-olinuxino/env/bin/boot
deleted file mode 100644
index 60dd93f297..0000000000
--- a/arch/arm/boards/imx233-olinuxino/env/bin/boot
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-. /env/config
-
-if [ x$1 = xdisk ]; then
- rootfs_loc=disk
- kernel_loc=disk
-elif [ x$1 = xnet ]; then
- rootfs_loc=net
- kernel_loc=net
-fi
-
-if [ x$ip = xdhcp ]; then
- bootargs="$bootargs ip=dhcp"
-elif [ x$ip = xnone ]; then
- bootargs="$bootargs ip=none"
-else
- bootargs="$bootargs ip=$eth0.ipaddr::$eth0.gateway:$eth0.netmask:::"
-fi
-
-if [ x$rootfs_loc = xdisk ]; then
- bootargs="$bootargs noinitrd rootfstype=$rootfs_type root=/dev/$rootfs_part"
-elif [ x$rootfs_loc = xnet ]; then
- bootargs="$bootargs root=/dev/nfs nfsroot=$nfsroot,v3,tcp noinitrd"
-elif [ x$rootfs_loc = xinitrd ]; then
- bootargs="$bootargs root=/dev/ram0 rdinit=/sbin/init"
-fi
-
-
-bootm -o $oftree_loc/imx23-olinuxino.dtb /dev/$kernel_part
-
-echo "Booting failed. Correct setup of 'kernel_part'?"
diff --git a/arch/arm/boards/imx233-olinuxino/env/bin/init b/arch/arm/boards/imx233-olinuxino/env/bin/init
deleted file mode 100644
index 3ed68f76c5..0000000000
--- a/arch/arm/boards/imx233-olinuxino/env/bin/init
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-PATH=/env/bin
-export PATH
-
-. /env/config
-
-echo
-echo -n "Hit any key to stop autoboot: "
-timeout -a $autoboot_timeout
-if [ $? != 0 ]; then
- exit
-fi
-
-boot
diff --git a/arch/arm/boards/imx233-olinuxino/env/config b/arch/arm/boards/imx233-olinuxino/env/config
deleted file mode 100644
index c84014ff58..0000000000
--- a/arch/arm/boards/imx233-olinuxino/env/config
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-
-# use 'dhcp' to do dhcp in barebox and in kernel
-# use 'none' if you want to skip kernel ip autoconfiguration
-ip=none
-
-# or set your networking parameters here (if a USB network adapter is attached)
-#eth0.ipaddr=a.b.c.d
-#eth0.netmask=a.b.c.d
-#eth0.gateway=a.b.c.d
-#eth0.serverip=a.b.c.d
-
-# can be either 'net' or 'disk'
-kernel_loc=disk
-
-# can be either 'net', or 'disk' or 'initrd'
-rootfs_loc=disk
-
-# can be any regular filesystem like ext2, ext3, reiserfs in case of 'rootfs_loc=disk'
-rootfs_type=ext3
-
-# Where is the rootfs in case of 'rootfs_loc=disk'
-rootfs_part=mmcblk0p4
-
-# Where is the rootfs in case of 'rootfs_loc=net'
-nfsroot=FIXME
-
-# Where to get the kernel image in case of 'kernel_loc=disk'
-kernel_part=disk0.2
-
-# Where to get the device tree image in case of 'kernel_loc=disk'
-oftree_loc=env/oftree
-
-# base kernel parameter
-bootargs="console=ttyAMA0,115200 rw rootwait"
-
-autoboot_timeout=2
-
-# set a fancy prompt (if support is compiled in)
-PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m "
diff --git a/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c b/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c
index fa95d72339..b87a6764f3 100644
--- a/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c
+++ b/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c
@@ -20,6 +20,7 @@
#include <common.h>
#include <init.h>
#include <gpio.h>
+#include <led.h>
#include <environment.h>
#include <envfs.h>
#include <errno.h>
@@ -39,60 +40,6 @@ static struct mxs_mci_platform_data mci_pdata = {
.f_min = 400000,
};
-static const uint32_t pad_setup[] = {
- /* debug port */
- PWM1_DUART_TX | STRENGTH(S4MA), /* PWM0/DUART_TXD - U_DEBUG PIN 2 */
- PWM0_DUART_RX | STRENGTH(S4MA), /* PWM0/DUART_RXD - U_DEBUG PIN 1 */
-
- /* auart */
- I2C_SDA_AUART1_RX | STRENGTH(S4MA),
- I2C_CLK_AUART1_TX | STRENGTH(S4MA),
-
- /* lcd */
- LCD_D17 | STRENGTH(S12MA), /*PIN18/LCD_D17 - GPIO PIN 3 */
- LCD_D16 | STRENGTH(S12MA),
- LCD_D15 | STRENGTH(S12MA),
- LCD_D14 | STRENGTH(S12MA),
- LCD_D13 | STRENGTH(S12MA),
- LCD_D12 | STRENGTH(S12MA),
- LCD_D11 | STRENGTH(S12MA),
- LCD_D10 | STRENGTH(S12MA),
- LCD_D9 | STRENGTH(S12MA),
- LCD_D8 | STRENGTH(S12MA),
- LCD_D7 | STRENGTH(S12MA),
- LCD_D6 | STRENGTH(S12MA),
- LCD_D5 | STRENGTH(S12MA),
- LCD_D4 | STRENGTH(S12MA),
- LCD_D3 | STRENGTH(S12MA),
- LCD_D2 | STRENGTH(S12MA), /* PIN3/LCD_D02 - GPIO PIN 31*/
- LCD_D1 | STRENGTH(S12MA), /* PIN2/LCD_D01 - GPIO PIN 33*/
- LCD_D0 | STRENGTH(S12MA), /* PIN1/LCD_D00 - GPIO PIN 35*/
- LCD_CS, /* PIN26/LCD_CS - GPIO PIN 20*/
- LCD_RS, /* PIN25/LCD_RS - GPIO PIN 18*/
- LCD_WR, /* PIN24/LCD_WR - GPIO PIN 16*/
- LCD_RESET, /* PIN23/LCD_DISP - GPIO PIN 14*/
- LCD_ENABE | STRENGTH(S12MA), /* PIN22/LCD_EN/I2C_SCL - GPIO PIN 12*/
- LCD_VSYNC | STRENGTH(S12MA), /* PIN21/LCD_HSYNC/I2C_SDA- GPIO PIN 10*/
- LCD_HSYNC | STRENGTH(S12MA), /* PIN20/LCD_VSYNC - GPIO PIN 8*/
- LCD_DOTCLOCK | STRENGTH(S12MA), /* PIN19/LCD_DOTCLK - GPIO PIN 6*/
-
-
- /* SD card interface */
- SSP1_DATA0 | PULLUP(1),
- SSP1_DATA1 | PULLUP(1),
- SSP1_DATA2 | PULLUP(1),
- SSP1_DATA3 | PULLUP(1),
- SSP1_SCK,
- SSP1_CMD | PULLUP(1),
- SSP1_DETECT | PULLUP(1),
-
- /* led */
- SSP1_DETECT_GPIO | GPIO_OUT | GPIO_VALUE(1),
-
- /* gpio - USB hub LAN9512-JZX*/
- GPMI_ALE_GPIO | GPIO_OUT | GPIO_VALUE(1),
-};
-
static int imx23_olinuxino_mem_init(void)
{
arm_add_mem_device("ram0", IMX_MEMORY_BASE, 64 * 1024 * 1024);
@@ -103,21 +50,25 @@ mem_initcall(imx23_olinuxino_mem_init);
static void olinuxino_init_usb(void)
{
-
imx23_usb_phy_enable();
add_generic_usb_ehci_device(DEVICE_ID_DYNAMIC, IMX_USB_BASE, NULL);
}
+static struct gpio_led led1 = {
+ .gpio = 65,
+ .led = {
+ .name = "led1",
+ }
+};
+
static int imx23_olinuxino_devices_init(void)
{
- int i;
-
- /* initizalize gpios */
- for (i = 0; i < ARRAY_SIZE(pad_setup); i++)
- imx_gpio_mode(pad_setup[i]);
-
armlinux_set_architecture(MACH_TYPE_IMX233_OLINUXINO);
+ defaultenv_append_directory(defaultenv_imx233_olinuxino);
+
+ led_gpio_register(&led1);
+ led_set_trigger(LED_TRIGGER_HEARTBEAT, &led1.led);
add_generic_device("mxs_mci", DEVICE_ID_DYNAMIC, NULL, IMX_SSP1_BASE,
0x8000, IORESOURCE_MEM, &mci_pdata);
diff --git a/arch/arm/boards/imx233-olinuxino/lowlevel.c b/arch/arm/boards/imx233-olinuxino/lowlevel.c
index bfc76cc7d4..6e4b830485 100644
--- a/arch/arm/boards/imx233-olinuxino/lowlevel.c
+++ b/arch/arm/boards/imx233-olinuxino/lowlevel.c
@@ -3,9 +3,175 @@
#include <asm/barebox-arm-head.h>
#include <asm/barebox-arm.h>
#include <mach/imx23-regs.h>
+#include <mach/init.h>
+#include <io.h>
+#include <debug_ll.h>
+#include <mach/iomux.h>
-void __naked barebox_arm_reset_vector(void)
+ENTRY_FUNCTION(start_barebox_olinuxino_imx23, r0, r1, r2)
{
- arm_cpu_lowlevel_init();
barebox_arm_entry(IMX_MEMORY_BASE, SZ_64M, NULL);
}
+
+static const uint32_t pad_setup[] = {
+ /* debug port */
+ PWM1_DUART_TX | STRENGTH(S4MA), /* PWM0/DUART_TXD - U_DEBUG PIN 2 */
+ PWM0_DUART_RX | STRENGTH(S4MA), /* PWM0/DUART_RXD - U_DEBUG PIN 1 */
+
+ /* SDRAM */
+ EMI_D0 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D1 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D2 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D3 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D4 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D5 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D6 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D7 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D8 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D9 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D10 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D11 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D12 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D13 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D14 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_D15 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_DQM0 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_DQM1 | VE_2_5V | STRENGTH(S12MA) | PULLUP(1),
+ EMI_DQS0 | VE_2_5V | STRENGTH(S12MA),
+ EMI_DQS1 | VE_2_5V | STRENGTH(S12MA),
+
+ EMI_CLK | VE_2_5V | STRENGTH(S12MA),
+ EMI_CLKN | VE_2_5V | STRENGTH(S12MA),
+ EMI_A0 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A1 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A2 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A3 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A4 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A5 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A6 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A7 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A8 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A9 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A10 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A11 | VE_2_5V | STRENGTH(S12MA),
+ EMI_A12 | VE_2_5V | STRENGTH(S12MA),
+ EMI_BA0 | VE_2_5V | STRENGTH(S12MA),
+ EMI_BA1 | VE_2_5V | STRENGTH(S12MA),
+
+ EMI_CASN | VE_2_5V | STRENGTH(S12MA),
+ EMI_CE0N | VE_2_5V | STRENGTH(S12MA),
+ EMI_CE1N | VE_2_5V | STRENGTH(S12MA),
+ EMI_CKE | VE_2_5V | STRENGTH(S12MA),
+ EMI_RASN | VE_2_5V | STRENGTH(S12MA),
+ EMI_WEN | VE_2_5V | STRENGTH(S12MA),
+
+ /* auart */
+ I2C_SDA_AUART1_RX | STRENGTH(S4MA),
+ I2C_CLK_AUART1_TX | STRENGTH(S4MA),
+
+ /* LCD */
+ LCD_D17 | STRENGTH(S12MA), /*PIN18/LCD_D17 - GPIO PIN 3 */
+ LCD_D16 | STRENGTH(S12MA),
+ LCD_D15 | STRENGTH(S12MA),
+ LCD_D14 | STRENGTH(S12MA),
+ LCD_D13 | STRENGTH(S12MA),
+ LCD_D12 | STRENGTH(S12MA),
+ LCD_D11 | STRENGTH(S12MA),
+ LCD_D10 | STRENGTH(S12MA),
+ LCD_D9 | STRENGTH(S12MA),
+ LCD_D8 | STRENGTH(S12MA),
+ LCD_D7 | STRENGTH(S12MA),
+ LCD_D6 | STRENGTH(S12MA),
+ LCD_D5 | STRENGTH(S12MA),
+ LCD_D4 | STRENGTH(S12MA),
+ LCD_D3 | STRENGTH(S12MA),
+ LCD_D2 | STRENGTH(S12MA), /* PIN3/LCD_D02 - GPIO PIN 31*/
+ LCD_D1 | STRENGTH(S12MA), /* PIN2/LCD_D01 - GPIO PIN 33*/
+ LCD_D0 | STRENGTH(S12MA), /* PIN1/LCD_D00 - GPIO PIN 35*/
+ LCD_CS, /* PIN26/LCD_CS - GPIO PIN 20*/
+ LCD_RS, /* PIN25/LCD_RS - GPIO PIN 18*/
+ LCD_WR, /* PIN24/LCD_WR - GPIO PIN 16*/
+ LCD_RESET, /* PIN23/LCD_DISP - GPIO PIN 14*/
+ LCD_ENABE | STRENGTH(S12MA), /* PIN22/LCD_EN/I2C_SCL - GPIO PIN 12*/
+ LCD_VSYNC | STRENGTH(S12MA), /* PIN21/LCD_HSYNC/I2C_SDA- GPIO PIN 10*/
+ LCD_HSYNC | STRENGTH(S12MA), /* PIN20/LCD_VSYNC - GPIO PIN 8*/
+ LCD_DOTCLOCK | STRENGTH(S12MA), /* PIN19/LCD_DOTCLK - GPIO PIN 6*/
+
+ /* SD card interface */
+ SSP1_DATA0 | PULLUP(1),
+ SSP1_DATA1 | PULLUP(1),
+ SSP1_DATA2 | PULLUP(1),
+ SSP1_DATA3 | PULLUP(1),
+ SSP1_SCK,
+ SSP1_CMD | PULLUP(1),
+ SSP1_DETECT | PULLUP(1),
+
+ /* LED */
+ SSP1_DETECT_GPIO | GPIO_OUT | GPIO_VALUE(1),
+
+ /* GPIO - USB hub LAN9512-JZX*/
+ GPMI_ALE_GPIO | GPIO_OUT | GPIO_VALUE(1),
+};
+
+
+/* Fine-tune the DRAM configuration. */
+void imx23_olinuxino_adjust_memory_params(uint32_t *dram_vals)
+{
+ /* Enable Auto Precharge. */
+ dram_vals[3] |= 1 << 8;
+ /* Enable Fast Writes. */
+ dram_vals[5] |= 1 << 8;
+ /* tEMRS = 3*tCK */
+ dram_vals[10] &= ~(0x3 << 8);
+ dram_vals[10] |= (0x3 << 8);
+ /* CASLAT = 3*tCK */
+ dram_vals[11] &= ~(0x3 << 0);
+ dram_vals[11] |= (0x3 << 0);
+ /* tCKE = 1*tCK */
+ dram_vals[12] &= ~(0x7 << 0);
+ dram_vals[12] |= (0x1 << 0);
+ /* CASLAT_LIN_GATE = 3*tCK , CASLAT_LIN = 3*tCK, tWTR=2*tCK */
+ dram_vals[13] &= ~((0xf << 16) | (0xf << 24) | (0xf << 0));
+ dram_vals[13] |= (0x6 << 16) | (0x6 << 24) | (0x2 << 0);
+ /* tDAL = 6*tCK */
+ dram_vals[15] &= ~(0xf << 16);
+ dram_vals[15] |= (0x6 << 16);
+ /* tREF = 1040*tCK */
+ dram_vals[26] &= ~0xffff;
+ dram_vals[26] |= 0x0410;
+ /* tRAS_MAX = 9334*tCK */
+ dram_vals[32] &= ~0xffff;
+ dram_vals[32] |= 0x2475;
+}
+
+static noinline void imx23_olinuxino_init(void)
+{
+ int i;
+
+ /* initizalize gpios */
+ for (i = 0; i < ARRAY_SIZE(pad_setup); i++)
+ imx_gpio_mode(pad_setup[i]);
+
+ pr_debug("initializing power...\n");
+
+ mx23_power_init();
+
+ pr_debug("initializing SDRAM...\n");
+
+ imx23_olinuxino_adjust_memory_params(mx23_dram_vals);
+ mx23_mem_init();
+
+ pr_debug("DONE\n");
+}
+
+ENTRY_FUNCTION(prep_start_barebox_olinuxino_imx23, r0, r1, r2)
+{
+ void (*back)(unsigned long) = (void *)get_lr();
+
+ relocate_to_current_adr();
+ setup_c();
+
+ imx23_olinuxino_init();
+
+ back(0);
+}
diff --git a/arch/arm/boards/karo-tx28/env/config b/arch/arm/boards/karo-tx28/env/config
deleted file mode 100644
index a6b10255a2..0000000000
--- a/arch/arm/boards/karo-tx28/env/config
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-#
-
-baseboard=tx28stk5
-
-# use 'dhcp' to do dhcp in barebox and in kernel
-# use 'none' if you want to skip kernel ip autoconfiguration
-ip=dhcp
-
-# or set your networking parameters here
-#eth0.ipaddr=a.b.c.d
-#eth0.ethaddr=de:ad:be:ef:00:00
-#eth0.netmask=a.b.c.d
-#eth0.serverip=a.b.c.d
-#eth0.gateway=a.b.c.d
-
-# can be either 'nfs' or 'tftp'
-kernel_loc=tftp
-# can be either 'net' or 'initrd'
-rootfs_loc=net
-
-# can be either 'jffs2' or 'ubifs'
-rootfs_type=ubifs
-rootfsimage=root-${global.hostname}.$rootfs_type
-
-kernelimage=zImage-${global.hostname}
-#kernelimage=uImage-${global.hostname}
-#kernelimage=Image-${global.hostname}
-#kernelimage=Image-${global.hostname}.lzo
-
-if [ -n $user ]; then
- kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
- rootfsimage="$user"-"$rootfsimage"
-else
- nfsroot="$eth0.serverip:/path/to/nfs/root"
-fi
-
-autoboot_timeout=3
-
-bootargs="console=ttyAM0,115200 tx28_base=$baseboard"
diff --git a/arch/arm/boards/karo-tx28/lowlevel.c b/arch/arm/boards/karo-tx28/lowlevel.c
index 3c7248ef65..c5fdda1902 100644
--- a/arch/arm/boards/karo-tx28/lowlevel.c
+++ b/arch/arm/boards/karo-tx28/lowlevel.c
@@ -1,11 +1,65 @@
+#define pr_fmt(fmt) "KARO TX28: " fmt
+#define DEBUG
+
#include <common.h>
#include <linux/sizes.h>
#include <asm/barebox-arm-head.h>
#include <asm/barebox-arm.h>
#include <mach/imx28-regs.h>
+#include <mach/init.h>
+#include <io.h>
+#include <debug_ll.h>
+#include <mach/iomux.h>
+#include <stmp-device.h>
-void __naked barebox_arm_reset_vector(void)
+ENTRY_FUNCTION(start_barebox_karo_tx28, r0, r1, r2)
{
- arm_cpu_lowlevel_init();
barebox_arm_entry(IMX_MEMORY_BASE, SZ_128M, NULL);
}
+
+static const uint32_t iomux_pads[] = {
+ /* EMI */
+ EMI_DATA0, EMI_DATA1, EMI_DATA2, EMI_DATA3, EMI_DATA4, EMI_DATA5,
+ EMI_DATA6, EMI_DATA7, EMI_DATA8, EMI_DATA9, EMI_DATA10, EMI_DATA11,
+ EMI_DATA12, EMI_DATA13, EMI_DATA14, EMI_DATA15, EMI_ODT0, EMI_DQM0,
+ EMI_ODT1, EMI_DQM1, EMI_DDR_OPEN_FB, EMI_CLK, EMI_DSQ0, EMI_DSQ1,
+ EMI_DDR_OPEN, EMI_A0, EMI_A1, EMI_A2, EMI_A3, EMI_A4, EMI_A5,
+ EMI_A6, EMI_A7, EMI_A8, EMI_A9, EMI_A10, EMI_A11, EMI_A12, EMI_A13,
+ EMI_A14, EMI_BA0, EMI_BA1, EMI_BA2, EMI_CASN, EMI_RASN, EMI_WEN,
+ EMI_CE0N, EMI_CE1N, EMI_CKE,
+
+ /* Debug UART */
+ AUART0_RTS_DUART_TX | VE_3_3V | STRENGTH(S8MA),
+ AUART0_CTS_DUART_RX | VE_3_3V | STRENGTH(S8MA),
+};
+
+static noinline void karo_tx28_init(void)
+{
+ int i;
+
+ /* initialize muxing */
+ for (i = 0; i < ARRAY_SIZE(iomux_pads); i++)
+ imx_gpio_mode(iomux_pads[i]);
+
+ pr_debug("initializing power...\n");
+
+ mx28_power_init_battery_input();
+
+ pr_debug("initializing SDRAM...\n");
+
+ mx28_mem_init();
+
+ pr_debug("DONE\n");
+}
+
+ENTRY_FUNCTION(prep_start_barebox_karo_tx28, r0, r1, r2)
+{
+ void (*back)(unsigned long) = (void *)get_lr();
+
+ relocate_to_current_adr();
+ setup_c();
+
+ karo_tx28_init();
+
+ back(0);
+}
diff --git a/arch/arm/configs/imx233-olinuxino_defconfig b/arch/arm/configs/imx233-olinuxino_defconfig
index 75b5911d6b..5aed6a9ca2 100644
--- a/arch/arm/configs/imx233-olinuxino_defconfig
+++ b/arch/arm/configs/imx233-olinuxino_defconfig
@@ -1,52 +1,89 @@
CONFIG_ARCH_MXS=y
CONFIG_MACH_IMX233_OLINUXINO=y
+CONFIG_MXS_OCOTP=y
CONFIG_AEABI=y
CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
-CONFIG_BROKEN=y
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-CONFIG_LONGHELP=y
+CONFIG_ARM_UNWIND=y
+CONFIG_MMU=y
+CONFIG_TEXT_BASE=0x0
+CONFIG_MALLOC_SIZE=0x1000000
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_RELOCATABLE=y
+CONFIG_HUSH_FANCY_PROMPT=y
CONFIG_CMDLINE_EDITING=y
CONFIG_AUTO_COMPLETE=y
CONFIG_MENU=y
+CONFIG_BLSPEC=y
+CONFIG_DEFAULT_COMPRESSION_LZO=y
CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
-CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/imx233-olinuxino/env"
-CONFIG_BAREBOXENV_TARGET=y
+CONFIG_RESET_SOURCE=y
CONFIG_DEBUG_INFO=y
-CONFIG_ENABLE_FLASH_NOISE=y
-CONFIG_ENABLE_PARTITION_NOISE=y
-CONFIG_ENABLE_DEVICE_NOISE=y
-CONFIG_CMD_EDIT=y
-CONFIG_CMD_SLEEP=y
-CONFIG_CMD_SAVEENV=y
-CONFIG_CMD_EXPORT=y
-CONFIG_CMD_PRINTENV=y
-CONFIG_CMD_READLINE=y
-CONFIG_CMD_ECHO_E=y
-CONFIG_CMD_MTEST=y
-CONFIG_CMD_MTEST_ALTERNATIVE=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_IMD=y
+CONFIG_CMD_MEMINFO=y
CONFIG_CMD_BOOTM_SHOW_TYPE=y
CONFIG_CMD_BOOTM_VERBOSE=y
CONFIG_CMD_BOOTM_INITRD=y
CONFIG_CMD_BOOTM_OFTREE=y
CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y
-CONFIG_CMD_UIMAGE=y
-CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_BOOTU is not set
+CONFIG_CMD_GO=y
CONFIG_CMD_RESET=y
-CONFIG_CMD_OFTREE=y
-CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
-CONFIG_NET=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_DEFAULTENV=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_CMP=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_SHA1SUM=y
+CONFIG_CMD_SHA224SUM=y
+CONFIG_CMD_SHA256SUM=y
+CONFIG_CMD_UNCOMPRESS=y
+CONFIG_CMD_LET=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_READF=y
+CONFIG_CMD_SLEEP=y
CONFIG_CMD_DHCP=y
-CONFIG_NET_NFS=y
+CONFIG_CMD_HOST=y
CONFIG_CMD_PING=y
-CONFIG_NET_TFTP=y
-CONFIG_NET_TFTP_PUSH=y
+CONFIG_CMD_TFTP=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_MENU=y
+CONFIG_CMD_MENU_MANAGEMENT=y
+CONFIG_CMD_MENUTREE=y
+CONFIG_CMD_SPLASH=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_2048=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OF_DISPLAY_TIMINGS=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_NET=y
+CONFIG_NET_NFS=y
CONFIG_NET_NETCONSOLE=y
-CONFIG_NET_RESOLV=y
+CONFIG_DRIVER_SERIAL_AUART=y
CONFIG_NET_USB=y
CONFIG_NET_USB_SMSC95XX=y
-CONFIG_DISK_INTF_PLATFORM_IDE=y
+# CONFIG_SPI is not set
CONFIG_USB_HOST=y
CONFIG_USB_EHCI=y
CONFIG_USB_STORAGE=y
@@ -56,8 +93,15 @@ CONFIG_MCI=y
CONFIG_MCI_STARTUP=y
CONFIG_MCI_MXS=y
CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_LED_TRIGGERS=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_MXS_APBH_DMA=y
+CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_FAT_LFN=y
+CONFIG_ZLIB=y
+CONFIG_LZO_DECOMPRESS=y
diff --git a/arch/arm/configs/tx28stk5_defconfig b/arch/arm/configs/tx28stk5_defconfig
index fe80d98bbb..d5714f2ec4 100644
--- a/arch/arm/configs/tx28stk5_defconfig
+++ b/arch/arm/configs/tx28stk5_defconfig
@@ -4,58 +4,92 @@ CONFIG_AEABI=y
CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
CONFIG_ARM_UNWIND=y
CONFIG_MMU=y
-CONFIG_MALLOC_SIZE=0x01000000
-CONFIG_BROKEN=y
+CONFIG_TEXT_BASE=0x0
+CONFIG_MALLOC_SIZE=0x0
CONFIG_MALLOC_TLSF=y
CONFIG_KALLSYMS=y
-CONFIG_LONGHELP=y
-CONFIG_GLOB=y
+CONFIG_RELOCATABLE=y
CONFIG_HUSH_FANCY_PROMPT=y
CONFIG_CMDLINE_EDITING=y
CONFIG_AUTO_COMPLETE=y
CONFIG_MENU=y
-CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y
-CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/karo-tx28/env"
+CONFIG_BLSPEC=y
+CONFIG_IMD=y
+CONFIG_DEFAULT_COMPRESSION_LZO=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_RESET_SOURCE=y
CONFIG_DEBUG_INFO=y
-CONFIG_CMD_EDIT=y
-CONFIG_CMD_SLEEP=y
-CONFIG_CMD_SAVEENV=y
-CONFIG_CMD_LOADENV=y
-CONFIG_CMD_EXPORT=y
-CONFIG_CMD_PRINTENV=y
-CONFIG_CMD_READLINE=y
-CONFIG_CMD_TIME=y
-CONFIG_CMD_ECHO_E=y
+CONFIG_DEBUG_LL=y
+CONFIG_PBL_CONSOLE=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
CONFIG_CMD_IOMEM=y
-CONFIG_CMD_MTEST=y
-CONFIG_CMD_MTEST_ALTERNATIVE=y
+CONFIG_CMD_MEMINFO=y
CONFIG_CMD_BOOTM_SHOW_TYPE=y
CONFIG_CMD_BOOTM_VERBOSE=y
CONFIG_CMD_BOOTM_INITRD=y
CONFIG_CMD_BOOTM_OFTREE=y
CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y
-CONFIG_CMD_UIMAGE=y
-CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
-CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_UIMAGE=y
CONFIG_CMD_PARTITION=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_DEFAULTENV=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_SPLASH=y
-CONFIG_CMD_GPIO=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_CMP=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_SHA1SUM=y
+CONFIG_CMD_SHA224SUM=y
+CONFIG_CMD_SHA256SUM=y
CONFIG_CMD_UNCOMPRESS=y
-CONFIG_NET=y
+CONFIG_CMD_LET=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_READF=y
+CONFIG_CMD_SLEEP=y
CONFIG_CMD_DHCP=y
+CONFIG_CMD_HOST=y
+CONFIG_CMD_MIITOOL=y
+CONFIG_CMD_PING=y
CONFIG_CMD_TFTP=y
-CONFIG_FS_TFTP=y
-CONFIG_NET_RESOLV=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_MENUTREE=y
+CONFIG_CMD_SPLASH=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_2048=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OF_DISPLAY_TIMINGS=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_NET=y
+CONFIG_DRIVER_SERIAL_AUART=y
CONFIG_DRIVER_NET_FEC_IMX=y
# CONFIG_SPI is not set
+CONFIG_MTD=y
CONFIG_VIDEO=y
CONFIG_DRIVER_VIDEO_STM=y
CONFIG_MCI=y
CONFIG_MCI_STARTUP=y
CONFIG_MCI_MXS=y
+CONFIG_MXS_APBH_DMA=y
+CONFIG_FS_EXT4=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
CONFIG_FS_FAT=y
CONFIG_FS_FAT_WRITE=y
CONFIG_FS_FAT_LFN=y
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index f6061f4c2a..418870fb69 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*
*/
+#define pr_fmt(fmt) "start.c: " fmt
#include <common.h>
#include <init.h>
@@ -62,6 +63,8 @@ static noinline __noreturn void __start(unsigned long membase,
setup_c();
+ pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
+
barebox_boarddata = boarddata;
arm_stack_top = endmem;
endmem -= STACK_SIZE; /* Stack */
@@ -74,6 +77,7 @@ static noinline __noreturn void __start(unsigned long membase,
if (IS_ENABLED(CONFIG_PBL_IMAGE)) {
arm_set_cache_functions();
} else {
+ pr_debug("enabling MMU, ttb @ 0x%08lx\n", endmem);
arm_early_mmu_cache_invalidate();
mmu_early_enable(membase, memsize, endmem);
}
@@ -87,6 +91,8 @@ static noinline __noreturn void __start(unsigned long membase,
uint32_t totalsize = get_unaligned_be32(boarddata + 4);
endmem -= ALIGN(totalsize, 64);
barebox_boot_dtb = (void *)endmem;
+ pr_debug("found DTB in boarddata, copying to 0x%p\n",
+ barebox_boot_dtb);
memcpy(barebox_boot_dtb, boarddata, totalsize);
}
@@ -115,8 +121,13 @@ static noinline __noreturn void __start(unsigned long membase,
malloc_start = malloc_end - SZ_1G;
}
+ pr_debug("initializing malloc pool at 0x%08lx (size 0x%08lx)\n",
+ malloc_start, malloc_end - malloc_start);
+
mem_malloc_init((void *)malloc_start, (void *)malloc_end - 1);
+ pr_debug("starting barebox...\n");
+
start_barebox();
}
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index ab194e187e..b0b7c6d097 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -17,6 +17,7 @@
* GNU General Public License for more details.
*
*/
+#define pr_fmt(fmt) "uncompress.c: " fmt
#include <common.h>
#include <init.h>
@@ -76,9 +77,12 @@ static void __noreturn noinline uncompress_start_payload(unsigned long membase,
setup_c();
+ pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
+
if (IS_ENABLED(CONFIG_MMU_EARLY)) {
endmem &= ~0x3fff;
endmem -= SZ_16K; /* ttb */
+ pr_debug("enabling MMU, ttb @ 0x%08x\n", endmem);
mmu_early_enable(membase, memsize, endmem);
}
@@ -93,6 +97,9 @@ static void __noreturn noinline uncompress_start_payload(unsigned long membase,
pg_start = image_end + 1;
pg_len = *(image_end);
+ pr_debug("uncompressing barebox binary at 0x%p (size 0x%08x) to 0x%08lx\n",
+ pg_start, pg_len, barebox_base);
+
pbl_barebox_uncompress((void*)barebox_base, pg_start, pg_len);
arm_early_mmu_cache_flush();
@@ -103,6 +110,8 @@ static void __noreturn noinline uncompress_start_payload(unsigned long membase,
else
barebox = (void *)barebox_base;
+ pr_debug("jumping to uncompressed image at 0x%p\n", barebox);
+
barebox(membase, memsize, boarddata);
}
diff --git a/arch/arm/include/asm/common.h b/arch/arm/include/asm/common.h
index 133bb8e1f6..9ff3b19c7b 100644
--- a/arch/arm/include/asm/common.h
+++ b/arch/arm/include/asm/common.h
@@ -16,6 +16,32 @@ static inline unsigned long get_pc(void)
return pc;
}
+static inline unsigned long get_lr(void)
+{
+ unsigned long lr;
+
+ __asm__ __volatile__(
+ "mov %0, lr\n"
+ : "=r" (lr)
+ :
+ : "memory");
+
+ return lr;
+}
+
+static inline unsigned long get_sp(void)
+{
+ unsigned long sp;
+
+ __asm__ __volatile__(
+ "mov %0, sp\n"
+ : "=r" (sp)
+ :
+ : "memory");
+
+ return sp;
+}
+
static inline void arm_setup_stack(unsigned long top)
{
__asm__ __volatile__("mov sp, %0" : : "r"(top));
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index ccf1f59013..850a99c6d9 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -12,4 +12,61 @@ extern void memcpy_fromio(void *, const volatile void __iomem *, size_t);
extern void memcpy_toio(volatile void __iomem *, const void *, size_t);
extern void memset_io(volatile void __iomem *, int, size_t);
+/*
+ * Clear and set bits in one shot. These macros can be used to clear and
+ * set multiple bits in a register using a single call. These macros can
+ * also be used to set a multiple-bit bit pattern using a mask, by
+ * specifying the mask in the 'clear' parameter and the new bit pattern
+ * in the 'set' parameter.
+ */
+
+#define out_arch(type,endian,a,v) __raw_write##type(cpu_to_##endian(v),a)
+#define in_arch(type,endian,a) endian##_to_cpu(__raw_read##type(a))
+
+#define out_le64(a,v) out_arch(q,le64,a,v)
+#define out_le32(a,v) out_arch(l,le32,a,v)
+#define out_le16(a,v) out_arch(w,le16,a,v)
+
+#define in_le64(a) in_arch(q,le64,a)
+#define in_le32(a) in_arch(l,le32,a)
+#define in_le16(a) in_arch(w,le16,a)
+
+#define out_be32(a,v) out_arch(l,be32,a,v)
+#define out_be16(a,v) out_arch(w,be16,a,v)
+
+#define in_be32(a) in_arch(l,be32,a)
+#define in_be16(a) in_arch(w,be16,a)
+
+#define out_8(a,v) __raw_writeb(v,a)
+#define in_8(a) __raw_readb(a)
+
+#define clrbits(type, addr, clear) \
+ out_##type((addr), in_##type(addr) & ~(clear))
+
+#define setbits(type, addr, set) \
+ out_##type((addr), in_##type(addr) | (set))
+
+#define clrsetbits(type, addr, clear, set) \
+ out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
+
+#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
+#define setbits_be32(addr, set) setbits(be32, addr, set)
+#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
+
+#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
+#define setbits_le32(addr, set) setbits(le32, addr, set)
+#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
+
+#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
+#define setbits_be16(addr, set) setbits(be16, addr, set)
+#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
+
+#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
+#define setbits_le16(addr, set) setbits(le16, addr, set)
+#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
+
+#define clrbits_8(addr, clear) clrbits(8, addr, clear)
+#define setbits_8(addr, set) setbits(8, addr, set)
+#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
+
#endif /* __ASM_ARM_IO_H */
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 214f9404df..4022710007 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -45,6 +45,8 @@ config MACH_CHUMBY
config MACH_IMX233_OLINUXINO
bool "Olimex.ltd imx223-olinuxino"
+ select HAVE_DEFAULT_ENVIRONMENT_NEW
+ select HAVE_PBL_MULTI_IMAGES
help
Say Y here if you are using the imx233-olinuxino
@@ -59,6 +61,8 @@ choice
config MACH_TX28
bool "KARO tx28"
+ select HAVE_DEFAULT_ENVIRONMENT_NEW
+ select HAVE_PBL_MULTI_IMAGES
help
Say Y here if you are using the KARO TX28 CPU module.
@@ -134,4 +138,11 @@ endif
endmenu
+config ARCH_MXS_USBLOADER
+ bool "compile mxs-usb-loader"
+ help
+ mxs-usb-loader is a tool to upload and start mxs bootstream images to an
+ i.MX SoC in ROM boot mode. It requires libusb, so make sure you have the libusb
+ devel package installed on your machine.
+
endif
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index bd6892ed22..e3843368c2 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -1,5 +1,7 @@
obj-y += imx.o iomux-imx.o power.o
+pbl-y += iomux-imx.o
obj-$(CONFIG_ARCH_IMX23) += clocksource-imx23.o usb-imx23.o soc-imx23.o
obj-$(CONFIG_ARCH_IMX28) += clocksource-imx28.o usb-imx28.o soc-imx28.o
obj-$(CONFIG_MXS_OCOTP) += ocotp.o
obj-$(CONFIG_MXS_CMD_BCB) += bcb.o
+pbl-y += power-init.o mem-init.o lradc-init.o
diff --git a/arch/arm/mach-mxs/clocksource-imx23.c b/arch/arm/mach-mxs/clocksource-imx23.c
index d9b7c1a570..8279ee2f2d 100644
--- a/arch/arm/mach-mxs/clocksource-imx23.c
+++ b/arch/arm/mach-mxs/clocksource-imx23.c
@@ -17,7 +17,7 @@
#include <init.h>
#include <clock.h>
#include <notifier.h>
-#include <mach/imx-regs.h>
+#include <mach/imx23-regs.h>
#include <mach/clock.h>
#include <io.h>
diff --git a/arch/arm/mach-mxs/clocksource-imx28.c b/arch/arm/mach-mxs/clocksource-imx28.c
index d26aa93c36..4f38af68b4 100644
--- a/arch/arm/mach-mxs/clocksource-imx28.c
+++ b/arch/arm/mach-mxs/clocksource-imx28.c
@@ -16,7 +16,7 @@
#include <init.h>
#include <clock.h>
#include <notifier.h>
-#include <mach/imx-regs.h>
+#include <mach/imx28-regs.h>
#include <mach/clock.h>
#include <io.h>
diff --git a/arch/arm/mach-mxs/include/mach/imx23-regs.h b/arch/arm/mach-mxs/include/mach/imx23-regs.h
index 7fb664b334..3fd2f3d15b 100644
--- a/arch/arm/mach-mxs/include/mach/imx23-regs.h
+++ b/arch/arm/mach-mxs/include/mach/imx23-regs.h
@@ -24,9 +24,11 @@
#define IMX_DBGUART_BASE 0x80070000
#define IMX_TIM1_BASE 0x80068000
#define IMX_IOMUXC_BASE 0x80018000
+#define IMX_EMI_BASE 0x80020000
#define IMX_OCOTP_BASE 0x8002c000
#define IMX_WDT_BASE 0x8005c000
#define IMX_CCM_BASE 0x80040000
+#define IMX_LRADC_BASE 0x80050000
#define IMX_I2C1_BASE 0x80058000
#define IMX_SSP1_BASE 0x80010000
#define IMX_FB_BASE 0x80030000
@@ -35,5 +37,6 @@
#define IMX_USBPHY_BASE 0x8007c000
#define IMX_DIGCTL_BASE 0x8001c000
#define IMX_USB_BASE 0x80080000
+#define IMX_SDRAMC_BASE 0x800e0000
#endif /* __ASM_ARCH_MX23_REGS_H */
diff --git a/arch/arm/mach-mxs/include/mach/imx28-regs.h b/arch/arm/mach-mxs/include/mach/imx28-regs.h
index 088282963d..de0d882414 100644
--- a/arch/arm/mach-mxs/include/mach/imx28-regs.h
+++ b/arch/arm/mach-mxs/include/mach/imx28-regs.h
@@ -25,10 +25,12 @@
#define IMX_SSP3_BASE 0x80016000
#define IMX_IOMUXC_BASE 0x80018000
#define IMX_DIGCTL_BASE 0x8001c000
+#define IMX_EMI_BASE 0x80020000
#define IMX_OCOTP_BASE 0x8002c000
#define IMX_FB_BASE 0x80030000
#define IMX_CCM_BASE 0x80040000
#define IMX_POWER_BASE 0x80044000
+#define IMX_LRADC_BASE 0x80050000
#define IMX_WDT_BASE 0x80056000
#define IMX_I2C0_BASE 0x80058000
#define IMX_I2C1_BASE 0x8005a000
@@ -43,6 +45,7 @@
#define IMX_USBPHY1_BASE 0x8007e000
#define IMX_USB0_BASE 0x80080000
#define IMX_USB1_BASE 0x80090000
+#define IMX_SDRAMC_BASE 0x800e0000
#define IMX_FEC0_BASE 0x800F0000
#define IMX_FEC1_BASE 0x800F4000
diff --git a/arch/arm/mach-mxs/include/mach/init.h b/arch/arm/mach-mxs/include/mach/init.h
new file mode 100644
index 0000000000..1f9d8d48c0
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/init.h
@@ -0,0 +1,33 @@
+/*
+ * Freescale i.MX28 SPL functions
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __M28_INIT_H__
+#define __M28_INIT_H__
+
+void mxs_early_delay(int delay);
+
+void mx23_power_init(void);
+void mx23_power_init_battery_input(void);
+void mx28_power_init(void);
+void mx28_power_init_battery_input(void);
+void mxs_power_wait_pswitch(void);
+
+extern uint32_t mx28_dram_vals[];
+extern uint32_t mx23_dram_vals[];
+
+void mx23_mem_init(void);
+void mx28_mem_init(void);
+void mxs_mem_setup_cpu_and_hbus(void);
+void mxs_mem_setup_vdda(void);
+void mxs_mem_init_clock(unsigned char divider);
+
+void mxs_lradc_init(void);
+void mxs_lradc_enable_batt_measurement(void);
+
+#endif /* __M28_INIT_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/iomux.h b/arch/arm/mach-mxs/include/mach/iomux.h
index 4361be5782..0091dbae11 100644
--- a/arch/arm/mach-mxs/include/mach/iomux.h
+++ b/arch/arm/mach-mxs/include/mach/iomux.h
@@ -97,7 +97,7 @@
* .. PORTF(1, 15). So the PORTF macro is more ugly than necessary.
*/
# define PORTF(bank,bit) (BANK((bank) / 2) | BANKPIN((((bank) & 1) << 4) | (bit)) | ERROR((bit) & ~15) | ERROR((bank) & ~7))
-# define VE_2_5V VOLTAGE(1)
+# define VE_2_5V VOLTAGE(0)
# include <mach/iomux-imx23.h>
#endif
diff --git a/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h b/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h
new file mode 100644
index 0000000000..289b159b74
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h
@@ -0,0 +1,208 @@
+/*
+ * Freescale i.MX23 CLKCTRL Register Definitions
+ *
+ * Copyright (C) 2012 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * Based on code from LTIB:
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX23_REGS_CLKCTRL_H__
+#define __MX23_REGS_CLKCTRL_H__
+
+#include <mach/regs-common.h>
+
+#ifndef __ASSEMBLY__
+struct mxs_clkctrl_regs {
+ mxs_reg_32(hw_clkctrl_pll0ctrl0) /* 0x00 */
+ uint32_t hw_clkctrl_pll0ctrl1; /* 0x10 */
+ uint32_t reserved_pll0ctrl1[3]; /* 0x14-0x1c */
+ mxs_reg_32(hw_clkctrl_cpu) /* 0x20 */
+ mxs_reg_32(hw_clkctrl_hbus) /* 0x30 */
+ mxs_reg_32(hw_clkctrl_xbus) /* 0x40 */
+ mxs_reg_32(hw_clkctrl_xtal) /* 0x50 */
+ mxs_reg_32(hw_clkctrl_pix) /* 0x60 */
+ mxs_reg_32(hw_clkctrl_ssp0) /* 0x70 */
+ mxs_reg_32(hw_clkctrl_gpmi) /* 0x80 */
+ mxs_reg_32(hw_clkctrl_spdif) /* 0x90 */
+ mxs_reg_32(hw_clkctrl_emi) /* 0xa0 */
+
+ uint32_t reserved1[4];
+
+ mxs_reg_32(hw_clkctrl_saif0) /* 0xc0 */
+ mxs_reg_32(hw_clkctrl_tv) /* 0xd0 */
+ mxs_reg_32(hw_clkctrl_etm) /* 0xe0 */
+ mxs_reg_8(hw_clkctrl_frac0) /* 0xf0 */
+ mxs_reg_8(hw_clkctrl_frac1) /* 0x100 */
+ mxs_reg_32(hw_clkctrl_clkseq) /* 0x110 */
+ mxs_reg_32(hw_clkctrl_reset) /* 0x120 */
+ mxs_reg_32(hw_clkctrl_status) /* 0x130 */
+ mxs_reg_32(hw_clkctrl_version) /* 0x140 */
+};
+#endif
+
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_MASK (0x3 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_OFFSET 28
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_DEFAULT (0x0 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_TIMES_2 (0x1 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_TIMES_05 (0x2 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_UNDEFINED (0x3 << 28)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_MASK (0x3 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_OFFSET 24
+#define CLKCTRL_PLL0CTRL0_CP_SEL_DEFAULT (0x0 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_TIMES_2 (0x1 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_TIMES_05 (0x2 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_UNDEFINED (0x3 << 24)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_MASK (0x3 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_OFFSET 20
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_DEFAULT (0x0 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_LOWER (0x1 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_LOWEST (0x2 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_UNDEFINED (0x3 << 20)
+#define CLKCTRL_PLL0CTRL0_EN_USB_CLKS (1 << 18)
+#define CLKCTRL_PLL0CTRL0_POWER (1 << 16)
+
+#define CLKCTRL_PLL0CTRL1_LOCK (1 << 31)
+#define CLKCTRL_PLL0CTRL1_FORCE_LOCK (1 << 30)
+#define CLKCTRL_PLL0CTRL1_LOCK_COUNT_MASK 0xffff
+#define CLKCTRL_PLL0CTRL1_LOCK_COUNT_OFFSET 0
+
+#define CLKCTRL_CPU_BUSY_REF_XTAL (1 << 29)
+#define CLKCTRL_CPU_BUSY_REF_CPU (1 << 28)
+#define CLKCTRL_CPU_DIV_XTAL_FRAC_EN (1 << 26)
+#define CLKCTRL_CPU_DIV_XTAL_MASK (0x3ff << 16)
+#define CLKCTRL_CPU_DIV_XTAL_OFFSET 16
+#define CLKCTRL_CPU_INTERRUPT_WAIT (1 << 12)
+#define CLKCTRL_CPU_DIV_CPU_FRAC_EN (1 << 10)
+#define CLKCTRL_CPU_DIV_CPU_MASK 0x3f
+#define CLKCTRL_CPU_DIV_CPU_OFFSET 0
+
+#define CLKCTRL_HBUS_BUSY (1 << 29)
+#define CLKCTRL_HBUS_DCP_AS_ENABLE (1 << 28)
+#define CLKCTRL_HBUS_PXP_AS_ENABLE (1 << 27)
+#define CLKCTRL_HBUS_APBHDMA_AS_ENABLE (1 << 26)
+#define CLKCTRL_HBUS_APBXDMA_AS_ENABLE (1 << 25)
+#define CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE (1 << 24)
+#define CLKCTRL_HBUS_TRAFFIC_AS_ENABLE (1 << 23)
+#define CLKCTRL_HBUS_CPU_DATA_AS_ENABLE (1 << 22)
+#define CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE (1 << 21)
+#define CLKCTRL_HBUS_AUTO_SLOW_MODE (1 << 20)
+#define CLKCTRL_HBUS_SLOW_DIV_MASK (0x7 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_OFFSET 16
+#define CLKCTRL_HBUS_SLOW_DIV_BY1 (0x0 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY2 (0x1 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY4 (0x2 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY8 (0x3 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY16 (0x4 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY32 (0x5 << 16)
+#define CLKCTRL_HBUS_DIV_FRAC_EN (1 << 5)
+#define CLKCTRL_HBUS_DIV_MASK 0x1f
+#define CLKCTRL_HBUS_DIV_OFFSET 0
+
+#define CLKCTRL_XBUS_BUSY (1 << 31)
+#define CLKCTRL_XBUS_DIV_FRAC_EN (1 << 10)
+#define CLKCTRL_XBUS_DIV_MASK 0x3ff
+#define CLKCTRL_XBUS_DIV_OFFSET 0
+
+#define CLKCTRL_XTAL_UART_CLK_GATE (1 << 31)
+#define CLKCTRL_XTAL_FILT_CLK24M_GATE (1 << 30)
+#define CLKCTRL_XTAL_PWM_CLK24M_GATE (1 << 29)
+#define CLKCTRL_XTAL_DRI_CLK24M_GATE (1 << 28)
+#define CLKCTRL_XTAL_DIGCTRL_CLK1M_GATE (1 << 27)
+#define CLKCTRL_XTAL_TIMROT_CLK32K_GATE (1 << 26)
+#define CLKCTRL_XTAL_DIV_UART_MASK 0x3
+#define CLKCTRL_XTAL_DIV_UART_OFFSET 0
+
+#define CLKCTRL_PIX_CLKGATE (1 << 31)
+#define CLKCTRL_PIX_BUSY (1 << 29)
+#define CLKCTRL_PIX_DIV_FRAC_EN (1 << 12)
+#define CLKCTRL_PIX_DIV_MASK 0xfff
+#define CLKCTRL_PIX_DIV_OFFSET 0
+
+#define CLKCTRL_SSP_CLKGATE (1 << 31)
+#define CLKCTRL_SSP_BUSY (1 << 29)
+#define CLKCTRL_SSP_DIV_FRAC_EN (1 << 9)
+#define CLKCTRL_SSP_DIV_MASK 0x1ff
+#define CLKCTRL_SSP_DIV_OFFSET 0
+
+#define CLKCTRL_GPMI_CLKGATE (1 << 31)
+#define CLKCTRL_GPMI_BUSY (1 << 29)
+#define CLKCTRL_GPMI_DIV_FRAC_EN (1 << 10)
+#define CLKCTRL_GPMI_DIV_MASK 0x3ff
+#define CLKCTRL_GPMI_DIV_OFFSET 0
+
+#define CLKCTRL_SPDIF_CLKGATE (1 << 31)
+
+#define CLKCTRL_EMI_CLKGATE (1 << 31)
+#define CLKCTRL_EMI_SYNC_MODE_EN (1 << 30)
+#define CLKCTRL_EMI_BUSY_REF_XTAL (1 << 29)
+#define CLKCTRL_EMI_BUSY_REF_EMI (1 << 28)
+#define CLKCTRL_EMI_BUSY_REF_CPU (1 << 27)
+#define CLKCTRL_EMI_BUSY_SYNC_MODE (1 << 26)
+#define CLKCTRL_EMI_BUSY_DCC_RESYNC (1 << 17)
+#define CLKCTRL_EMI_DCC_RESYNC_ENABLE (1 << 16)
+#define CLKCTRL_EMI_DIV_XTAL_MASK (0xf << 8)
+#define CLKCTRL_EMI_DIV_XTAL_OFFSET 8
+#define CLKCTRL_EMI_DIV_EMI_MASK 0x3f
+#define CLKCTRL_EMI_DIV_EMI_OFFSET 0
+
+#define CLKCTRL_IR_CLKGATE (1 << 31)
+#define CLKCTRL_IR_AUTO_DIV (1 << 29)
+#define CLKCTRL_IR_IR_BUSY (1 << 28)
+#define CLKCTRL_IR_IROV_BUSY (1 << 27)
+#define CLKCTRL_IR_IROV_DIV_MASK (0x1ff << 16)
+#define CLKCTRL_IR_IROV_DIV_OFFSET 16
+#define CLKCTRL_IR_IR_DIV_MASK 0x3ff
+#define CLKCTRL_IR_IR_DIV_OFFSET 0
+
+#define CLKCTRL_SAIF0_CLKGATE (1 << 31)
+#define CLKCTRL_SAIF0_BUSY (1 << 29)
+#define CLKCTRL_SAIF0_DIV_FRAC_EN (1 << 16)
+#define CLKCTRL_SAIF0_DIV_MASK 0xffff
+#define CLKCTRL_SAIF0_DIV_OFFSET 0
+
+#define CLKCTRL_TV_CLK_TV108M_GATE (1 << 31)
+#define CLKCTRL_TV_CLK_TV_GATE (1 << 30)
+
+#define CLKCTRL_ETM_CLKGATE (1 << 31)
+#define CLKCTRL_ETM_BUSY (1 << 29)
+#define CLKCTRL_ETM_DIV_FRAC_EN (1 << 6)
+#define CLKCTRL_ETM_DIV_MASK 0x3f
+#define CLKCTRL_ETM_DIV_OFFSET 0
+
+#define CLKCTRL_FRAC_CLKGATE (1 << 7)
+#define CLKCTRL_FRAC_STABLE (1 << 6)
+#define CLKCTRL_FRAC_FRAC_MASK 0x3f
+#define CLKCTRL_FRAC_FRAC_OFFSET 0
+#define CLKCTRL_FRAC0_CPU 0
+#define CLKCTRL_FRAC0_EMI 1
+#define CLKCTRL_FRAC0_PIX 2
+#define CLKCTRL_FRAC0_IO0 3
+#define CLKCTRL_FRAC1_VID 3
+
+#define CLKCTRL_CLKSEQ_BYPASS_ETM (1 << 8)
+#define CLKCTRL_CLKSEQ_BYPASS_CPU (1 << 7)
+#define CLKCTRL_CLKSEQ_BYPASS_EMI (1 << 6)
+#define CLKCTRL_CLKSEQ_BYPASS_SSP0 (1 << 5)
+#define CLKCTRL_CLKSEQ_BYPASS_GPMI (1 << 4)
+#define CLKCTRL_CLKSEQ_BYPASS_IR (1 << 3)
+#define CLKCTRL_CLKSEQ_BYPASS_PIX (1 << 1)
+#define CLKCTRL_CLKSEQ_BYPASS_SAIF (1 << 0)
+
+#define CLKCTRL_RESET_CHIP (1 << 1)
+#define CLKCTRL_RESET_DIG (1 << 0)
+
+#define CLKCTRL_STATUS_CPU_LIMIT_MASK (0x3 << 30)
+#define CLKCTRL_STATUS_CPU_LIMIT_OFFSET 30
+
+#define CLKCTRL_VERSION_MAJOR_MASK (0xff << 24)
+#define CLKCTRL_VERSION_MAJOR_OFFSET 24
+#define CLKCTRL_VERSION_MINOR_MASK (0xff << 16)
+#define CLKCTRL_VERSION_MINOR_OFFSET 16
+#define CLKCTRL_VERSION_STEP_MASK 0xffff
+#define CLKCTRL_VERSION_STEP_OFFSET 0
+
+#endif /* __MX23_REGS_CLKCTRL_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h b/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h
new file mode 100644
index 0000000000..aebb489d4b
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h
@@ -0,0 +1,283 @@
+/*
+ * Freescale i.MX28 CLKCTRL Register Definitions
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * Based on code from LTIB:
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX28_REGS_CLKCTRL_H__
+#define __MX28_REGS_CLKCTRL_H__
+
+#include <mach/regs-common.h>
+
+#ifndef __ASSEMBLY__
+struct mxs_clkctrl_regs {
+ mxs_reg_32(hw_clkctrl_pll0ctrl0) /* 0x00 */
+ uint32_t hw_clkctrl_pll0ctrl1; /* 0x10 */
+ uint32_t reserved_pll0ctrl1[3]; /* 0x14-0x1c */
+ mxs_reg_32(hw_clkctrl_pll1ctrl0) /* 0x20 */
+ uint32_t hw_clkctrl_pll1ctrl1; /* 0x30 */
+ uint32_t reserved_pll1ctrl1[3]; /* 0x34-0x3c */
+ mxs_reg_32(hw_clkctrl_pll2ctrl0) /* 0x40 */
+ mxs_reg_32(hw_clkctrl_cpu) /* 0x50 */
+ mxs_reg_32(hw_clkctrl_hbus) /* 0x60 */
+ mxs_reg_32(hw_clkctrl_xbus) /* 0x70 */
+ mxs_reg_32(hw_clkctrl_xtal) /* 0x80 */
+ mxs_reg_32(hw_clkctrl_ssp0) /* 0x90 */
+ mxs_reg_32(hw_clkctrl_ssp1) /* 0xa0 */
+ mxs_reg_32(hw_clkctrl_ssp2) /* 0xb0 */
+ mxs_reg_32(hw_clkctrl_ssp3) /* 0xc0 */
+ mxs_reg_32(hw_clkctrl_gpmi) /* 0xd0 */
+ mxs_reg_32(hw_clkctrl_spdif) /* 0xe0 */
+ mxs_reg_32(hw_clkctrl_emi) /* 0xf0 */
+ mxs_reg_32(hw_clkctrl_saif0) /* 0x100 */
+ mxs_reg_32(hw_clkctrl_saif1) /* 0x110 */
+ mxs_reg_32(hw_clkctrl_lcdif) /* 0x120 */
+ mxs_reg_32(hw_clkctrl_etm) /* 0x130 */
+ mxs_reg_32(hw_clkctrl_enet) /* 0x140 */
+ mxs_reg_32(hw_clkctrl_hsadc) /* 0x150 */
+ mxs_reg_32(hw_clkctrl_flexcan) /* 0x160 */
+
+ uint32_t reserved[16];
+
+ mxs_reg_8(hw_clkctrl_frac0) /* 0x1b0 */
+ mxs_reg_8(hw_clkctrl_frac1) /* 0x1c0 */
+ mxs_reg_32(hw_clkctrl_clkseq) /* 0x1d0 */
+ mxs_reg_32(hw_clkctrl_reset) /* 0x1e0 */
+ mxs_reg_32(hw_clkctrl_status) /* 0x1f0 */
+ mxs_reg_32(hw_clkctrl_version) /* 0x200 */
+};
+#endif
+
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_MASK (0x3 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_OFFSET 28
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_DEFAULT (0x0 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_TIMES_2 (0x1 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_TIMES_05 (0x2 << 28)
+#define CLKCTRL_PLL0CTRL0_LFR_SEL_UNDEFINED (0x3 << 28)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_MASK (0x3 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_OFFSET 24
+#define CLKCTRL_PLL0CTRL0_CP_SEL_DEFAULT (0x0 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_TIMES_2 (0x1 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_TIMES_05 (0x2 << 24)
+#define CLKCTRL_PLL0CTRL0_CP_SEL_UNDEFINED (0x3 << 24)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_MASK (0x3 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_OFFSET 20
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_DEFAULT (0x0 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_LOWER (0x1 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_LOWEST (0x2 << 20)
+#define CLKCTRL_PLL0CTRL0_DIV_SEL_UNDEFINED (0x3 << 20)
+#define CLKCTRL_PLL0CTRL0_EN_USB_CLKS (1 << 18)
+#define CLKCTRL_PLL0CTRL0_POWER (1 << 17)
+
+#define CLKCTRL_PLL0CTRL1_LOCK (1 << 31)
+#define CLKCTRL_PLL0CTRL1_FORCE_LOCK (1 << 30)
+#define CLKCTRL_PLL0CTRL1_LOCK_COUNT_MASK 0xffff
+#define CLKCTRL_PLL0CTRL1_LOCK_COUNT_OFFSET 0
+
+#define CLKCTRL_PLL1CTRL0_CLKGATEEMI (1 << 31)
+#define CLKCTRL_PLL1CTRL0_LFR_SEL_MASK (0x3 << 28)
+#define CLKCTRL_PLL1CTRL0_LFR_SEL_OFFSET 28
+#define CLKCTRL_PLL1CTRL0_LFR_SEL_DEFAULT (0x0 << 28)
+#define CLKCTRL_PLL1CTRL0_LFR_SEL_TIMES_2 (0x1 << 28)
+#define CLKCTRL_PLL1CTRL0_LFR_SEL_TIMES_05 (0x2 << 28)
+#define CLKCTRL_PLL1CTRL0_LFR_SEL_UNDEFINED (0x3 << 28)
+#define CLKCTRL_PLL1CTRL0_CP_SEL_MASK (0x3 << 24)
+#define CLKCTRL_PLL1CTRL0_CP_SEL_OFFSET 24
+#define CLKCTRL_PLL1CTRL0_CP_SEL_DEFAULT (0x0 << 24)
+#define CLKCTRL_PLL1CTRL0_CP_SEL_TIMES_2 (0x1 << 24)
+#define CLKCTRL_PLL1CTRL0_CP_SEL_TIMES_05 (0x2 << 24)
+#define CLKCTRL_PLL1CTRL0_CP_SEL_UNDEFINED (0x3 << 24)
+#define CLKCTRL_PLL1CTRL0_DIV_SEL_MASK (0x3 << 20)
+#define CLKCTRL_PLL1CTRL0_DIV_SEL_OFFSET 20
+#define CLKCTRL_PLL1CTRL0_DIV_SEL_DEFAULT (0x0 << 20)
+#define CLKCTRL_PLL1CTRL0_DIV_SEL_LOWER (0x1 << 20)
+#define CLKCTRL_PLL1CTRL0_DIV_SEL_LOWEST (0x2 << 20)
+#define CLKCTRL_PLL1CTRL0_DIV_SEL_UNDEFINED (0x3 << 20)
+#define CLKCTRL_PLL1CTRL0_EN_USB_CLKS (1 << 18)
+#define CLKCTRL_PLL1CTRL0_POWER (1 << 17)
+
+#define CLKCTRL_PLL1CTRL1_LOCK (1 << 31)
+#define CLKCTRL_PLL1CTRL1_FORCE_LOCK (1 << 30)
+#define CLKCTRL_PLL1CTRL1_LOCK_COUNT_MASK 0xffff
+#define CLKCTRL_PLL1CTRL1_LOCK_COUNT_OFFSET 0
+
+#define CLKCTRL_PLL2CTRL0_CLKGATE (1 << 31)
+#define CLKCTRL_PLL2CTRL0_LFR_SEL_MASK (0x3 << 28)
+#define CLKCTRL_PLL2CTRL0_LFR_SEL_OFFSET 28
+#define CLKCTRL_PLL2CTRL0_HOLD_RING_OFF_B (1 << 26)
+#define CLKCTRL_PLL2CTRL0_CP_SEL_MASK (0x3 << 24)
+#define CLKCTRL_PLL2CTRL0_CP_SEL_OFFSET 24
+#define CLKCTRL_PLL2CTRL0_POWER (1 << 23)
+
+#define CLKCTRL_CPU_BUSY_REF_XTAL (1 << 29)
+#define CLKCTRL_CPU_BUSY_REF_CPU (1 << 28)
+#define CLKCTRL_CPU_DIV_XTAL_FRAC_EN (1 << 26)
+#define CLKCTRL_CPU_DIV_XTAL_MASK (0x3ff << 16)
+#define CLKCTRL_CPU_DIV_XTAL_OFFSET 16
+#define CLKCTRL_CPU_INTERRUPT_WAIT (1 << 12)
+#define CLKCTRL_CPU_DIV_CPU_FRAC_EN (1 << 10)
+#define CLKCTRL_CPU_DIV_CPU_MASK 0x3f
+#define CLKCTRL_CPU_DIV_CPU_OFFSET 0
+
+#define CLKCTRL_HBUS_ASM_BUSY (1 << 31)
+#define CLKCTRL_HBUS_DCP_AS_ENABLE (1 << 30)
+#define CLKCTRL_HBUS_PXP_AS_ENABLE (1 << 29)
+#define CLKCTRL_HBUS_ASM_EMIPORT_AS_ENABLE (1 << 27)
+#define CLKCTRL_HBUS_APBHDMA_AS_ENABLE (1 << 26)
+#define CLKCTRL_HBUS_APBXDMA_AS_ENABLE (1 << 25)
+#define CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE (1 << 24)
+#define CLKCTRL_HBUS_TRAFFIC_AS_ENABLE (1 << 23)
+#define CLKCTRL_HBUS_CPU_DATA_AS_ENABLE (1 << 22)
+#define CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE (1 << 21)
+#define CLKCTRL_HBUS_ASM_ENABLE (1 << 20)
+#define CLKCTRL_HBUS_AUTO_CLEAR_DIV_ENABLE (1 << 19)
+#define CLKCTRL_HBUS_SLOW_DIV_MASK (0x7 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_OFFSET 16
+#define CLKCTRL_HBUS_SLOW_DIV_BY1 (0x0 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY2 (0x1 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY4 (0x2 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY8 (0x3 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY16 (0x4 << 16)
+#define CLKCTRL_HBUS_SLOW_DIV_BY32 (0x5 << 16)
+#define CLKCTRL_HBUS_DIV_FRAC_EN (1 << 5)
+#define CLKCTRL_HBUS_DIV_MASK 0x1f
+#define CLKCTRL_HBUS_DIV_OFFSET 0
+
+#define CLKCTRL_XBUS_BUSY (1 << 31)
+#define CLKCTRL_XBUS_AUTO_CLEAR_DIV_ENABLE (1 << 11)
+#define CLKCTRL_XBUS_DIV_FRAC_EN (1 << 10)
+#define CLKCTRL_XBUS_DIV_MASK 0x3ff
+#define CLKCTRL_XBUS_DIV_OFFSET 0
+
+#define CLKCTRL_XTAL_UART_CLK_GATE (1 << 31)
+#define CLKCTRL_XTAL_PWM_CLK24M_GATE (1 << 29)
+#define CLKCTRL_XTAL_TIMROT_CLK32K_GATE (1 << 26)
+#define CLKCTRL_XTAL_DIV_UART_MASK 0x3
+#define CLKCTRL_XTAL_DIV_UART_OFFSET 0
+
+#define CLKCTRL_SSP_CLKGATE (1 << 31)
+#define CLKCTRL_SSP_BUSY (1 << 29)
+#define CLKCTRL_SSP_DIV_FRAC_EN (1 << 9)
+#define CLKCTRL_SSP_DIV_MASK 0x1ff
+#define CLKCTRL_SSP_DIV_OFFSET 0
+
+#define CLKCTRL_GPMI_CLKGATE (1 << 31)
+#define CLKCTRL_GPMI_BUSY (1 << 29)
+#define CLKCTRL_GPMI_DIV_FRAC_EN (1 << 10)
+#define CLKCTRL_GPMI_DIV_MASK 0x3ff
+#define CLKCTRL_GPMI_DIV_OFFSET 0
+
+#define CLKCTRL_SPDIF_CLKGATE (1 << 31)
+
+#define CLKCTRL_EMI_CLKGATE (1 << 31)
+#define CLKCTRL_EMI_SYNC_MODE_EN (1 << 30)
+#define CLKCTRL_EMI_BUSY_REF_XTAL (1 << 29)
+#define CLKCTRL_EMI_BUSY_REF_EMI (1 << 28)
+#define CLKCTRL_EMI_BUSY_REF_CPU (1 << 27)
+#define CLKCTRL_EMI_BUSY_SYNC_MODE (1 << 26)
+#define CLKCTRL_EMI_BUSY_DCC_RESYNC (1 << 17)
+#define CLKCTRL_EMI_DCC_RESYNC_ENABLE (1 << 16)
+#define CLKCTRL_EMI_DIV_XTAL_MASK (0xf << 8)
+#define CLKCTRL_EMI_DIV_XTAL_OFFSET 8
+#define CLKCTRL_EMI_DIV_EMI_MASK 0x3f
+#define CLKCTRL_EMI_DIV_EMI_OFFSET 0
+
+#define CLKCTRL_SAIF0_CLKGATE (1 << 31)
+#define CLKCTRL_SAIF0_BUSY (1 << 29)
+#define CLKCTRL_SAIF0_DIV_FRAC_EN (1 << 16)
+#define CLKCTRL_SAIF0_DIV_MASK 0xffff
+#define CLKCTRL_SAIF0_DIV_OFFSET 0
+
+#define CLKCTRL_SAIF1_CLKGATE (1 << 31)
+#define CLKCTRL_SAIF1_BUSY (1 << 29)
+#define CLKCTRL_SAIF1_DIV_FRAC_EN (1 << 16)
+#define CLKCTRL_SAIF1_DIV_MASK 0xffff
+#define CLKCTRL_SAIF1_DIV_OFFSET 0
+
+#define CLKCTRL_DIS_LCDIF_CLKGATE (1 << 31)
+#define CLKCTRL_DIS_LCDIF_BUSY (1 << 29)
+#define CLKCTRL_DIS_LCDIF_DIV_FRAC_EN (1 << 13)
+#define CLKCTRL_DIS_LCDIF_DIV_MASK 0x1fff
+#define CLKCTRL_DIS_LCDIF_DIV_OFFSET 0
+
+#define CLKCTRL_ETM_CLKGATE (1 << 31)
+#define CLKCTRL_ETM_BUSY (1 << 29)
+#define CLKCTRL_ETM_DIV_FRAC_EN (1 << 7)
+#define CLKCTRL_ETM_DIV_MASK 0x7f
+#define CLKCTRL_ETM_DIV_OFFSET 0
+
+#define CLKCTRL_ENET_SLEEP (1 << 31)
+#define CLKCTRL_ENET_DISABLE (1 << 30)
+#define CLKCTRL_ENET_STATUS (1 << 29)
+#define CLKCTRL_ENET_BUSY_TIME (1 << 27)
+#define CLKCTRL_ENET_DIV_TIME_MASK (0x3f << 21)
+#define CLKCTRL_ENET_DIV_TIME_OFFSET 21
+#define CLKCTRL_ENET_TIME_SEL_MASK (0x3 << 19)
+#define CLKCTRL_ENET_TIME_SEL_OFFSET 19
+#define CLKCTRL_ENET_TIME_SEL_XTAL (0x0 << 19)
+#define CLKCTRL_ENET_TIME_SEL_PLL (0x1 << 19)
+#define CLKCTRL_ENET_TIME_SEL_RMII_CLK (0x2 << 19)
+#define CLKCTRL_ENET_TIME_SEL_UNDEFINED (0x3 << 19)
+#define CLKCTRL_ENET_CLK_OUT_EN (1 << 18)
+#define CLKCTRL_ENET_RESET_BY_SW_CHIP (1 << 17)
+#define CLKCTRL_ENET_RESET_BY_SW (1 << 16)
+
+#define CLKCTRL_HSADC_RESETB (1 << 30)
+#define CLKCTRL_HSADC_FREQDIV_MASK (0x3 << 28)
+#define CLKCTRL_HSADC_FREQDIV_OFFSET 28
+
+#define CLKCTRL_FLEXCAN_STOP_CAN0 (1 << 30)
+#define CLKCTRL_FLEXCAN_CAN0_STATUS (1 << 29)
+#define CLKCTRL_FLEXCAN_STOP_CAN1 (1 << 28)
+#define CLKCTRL_FLEXCAN_CAN1_STATUS (1 << 27)
+
+#define CLKCTRL_FRAC_CLKGATE (1 << 7)
+#define CLKCTRL_FRAC_STABLE (1 << 6)
+#define CLKCTRL_FRAC_FRAC_MASK 0x3f
+#define CLKCTRL_FRAC_FRAC_OFFSET 0
+#define CLKCTRL_FRAC0_CPU 0
+#define CLKCTRL_FRAC0_EMI 1
+#define CLKCTRL_FRAC0_IO1 2
+#define CLKCTRL_FRAC0_IO0 3
+#define CLKCTRL_FRAC1_PIX 0
+#define CLKCTRL_FRAC1_HSADC 1
+#define CLKCTRL_FRAC1_GPMI 2
+
+#define CLKCTRL_CLKSEQ_BYPASS_CPU (1 << 18)
+#define CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF (1 << 14)
+#define CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF_BYPASS (0x1 << 14)
+#define CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF_PFD (0x0 << 14)
+#define CLKCTRL_CLKSEQ_BYPASS_ETM (1 << 8)
+#define CLKCTRL_CLKSEQ_BYPASS_EMI (1 << 7)
+#define CLKCTRL_CLKSEQ_BYPASS_SSP3 (1 << 6)
+#define CLKCTRL_CLKSEQ_BYPASS_SSP2 (1 << 5)
+#define CLKCTRL_CLKSEQ_BYPASS_SSP1 (1 << 4)
+#define CLKCTRL_CLKSEQ_BYPASS_SSP0 (1 << 3)
+#define CLKCTRL_CLKSEQ_BYPASS_GPMI (1 << 2)
+#define CLKCTRL_CLKSEQ_BYPASS_SAIF1 (1 << 1)
+#define CLKCTRL_CLKSEQ_BYPASS_SAIF0 (1 << 0)
+
+#define CLKCTRL_RESET_WDOG_POR_DISABLE (1 << 5)
+#define CLKCTRL_RESET_EXTERNAL_RESET_ENABLE (1 << 4)
+#define CLKCTRL_RESET_THERMAL_RESET_ENABLE (1 << 3)
+#define CLKCTRL_RESET_THERMAL_RESET_DEFAULT (1 << 2)
+#define CLKCTRL_RESET_CHIP (1 << 1)
+#define CLKCTRL_RESET_DIG (1 << 0)
+
+#define CLKCTRL_STATUS_CPU_LIMIT_MASK (0x3 << 30)
+#define CLKCTRL_STATUS_CPU_LIMIT_OFFSET 30
+
+#define CLKCTRL_VERSION_MAJOR_MASK (0xff << 24)
+#define CLKCTRL_VERSION_MAJOR_OFFSET 24
+#define CLKCTRL_VERSION_MINOR_MASK (0xff << 16)
+#define CLKCTRL_VERSION_MINOR_OFFSET 16
+#define CLKCTRL_VERSION_STEP_MASK 0xffff
+#define CLKCTRL_VERSION_STEP_OFFSET 0
+
+#endif /* __MX28_REGS_CLKCTRL_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/regs-common.h b/arch/arm/mach-mxs/include/mach/regs-common.h
new file mode 100644
index 0000000000..e54a220fa3
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/regs-common.h
@@ -0,0 +1,69 @@
+/*
+ * Freescale i.MXS Register Accessors
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MXS_REGS_COMMON_H__
+#define __MXS_REGS_COMMON_H__
+
+/*
+ * The i.MXS has interesting feature when it comes to register access. There
+ * are four kinds of access to one particular register. Those are:
+ *
+ * 1) Common read/write access. To use this mode, just write to the address of
+ * the register.
+ * 2) Set bits only access. To set bits, write which bits you want to set to the
+ * address of the register + 0x4.
+ * 3) Clear bits only access. To clear bits, write which bits you want to clear
+ * to the address of the register + 0x8.
+ * 4) Toggle bits only access. To toggle bits, write which bits you want to
+ * toggle to the address of the register + 0xc.
+ *
+ * IMPORTANT NOTE: Not all registers support accesses 2-4! Also, not all bits
+ * can be set/cleared by pure write as in access type 1, some need to be
+ * explicitly set/cleared by using access type 2-3.
+ *
+ * The following macros and structures allow the user to either access the
+ * register in all aforementioned modes (by accessing reg_name, reg_name_set,
+ * reg_name_clr, reg_name_tog) or pass the register structure further into
+ * various functions with correct type information (by accessing reg_name_reg).
+ *
+ */
+
+#define __mxs_reg_8(name) \
+ uint8_t name[4]; \
+ uint8_t name##_set[4]; \
+ uint8_t name##_clr[4]; \
+ uint8_t name##_tog[4]; \
+
+#define __mxs_reg_32(name) \
+ uint32_t name; \
+ uint32_t name##_set; \
+ uint32_t name##_clr; \
+ uint32_t name##_tog;
+
+struct mxs_register_8 {
+ __mxs_reg_8(reg)
+};
+
+struct mxs_register_32 {
+ __mxs_reg_32(reg)
+};
+
+#define mxs_reg_8(name) \
+ union { \
+ struct { __mxs_reg_8(name) }; \
+ struct mxs_register_8 name##_reg; \
+ };
+
+#define mxs_reg_32(name) \
+ union { \
+ struct { __mxs_reg_32(name) }; \
+ struct mxs_register_32 name##_reg; \
+ };
+
+#endif /* __MXS_REGS_COMMON_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/regs-lradc.h b/arch/arm/mach-mxs/include/mach/regs-lradc.h
new file mode 100644
index 0000000000..7f624be4c5
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/regs-lradc.h
@@ -0,0 +1,387 @@
+/*
+ * Freescale i.MX28 LRADC Register Definitions
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * Based on code from LTIB:
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX28_REGS_LRADC_H__
+#define __MX28_REGS_LRADC_H__
+
+#include <mach/regs-common.h>
+
+#ifndef __ASSEMBLY__
+struct mxs_lradc_regs {
+ mxs_reg_32(hw_lradc_ctrl0);
+ mxs_reg_32(hw_lradc_ctrl1);
+ mxs_reg_32(hw_lradc_ctrl2);
+ mxs_reg_32(hw_lradc_ctrl3);
+ mxs_reg_32(hw_lradc_status);
+ mxs_reg_32(hw_lradc_ch0);
+ mxs_reg_32(hw_lradc_ch1);
+ mxs_reg_32(hw_lradc_ch2);
+ mxs_reg_32(hw_lradc_ch3);
+ mxs_reg_32(hw_lradc_ch4);
+ mxs_reg_32(hw_lradc_ch5);
+ mxs_reg_32(hw_lradc_ch6);
+ mxs_reg_32(hw_lradc_ch7);
+ mxs_reg_32(hw_lradc_delay0);
+ mxs_reg_32(hw_lradc_delay1);
+ mxs_reg_32(hw_lradc_delay2);
+ mxs_reg_32(hw_lradc_delay3);
+ mxs_reg_32(hw_lradc_debug0);
+ mxs_reg_32(hw_lradc_debug1);
+ mxs_reg_32(hw_lradc_conversion);
+ mxs_reg_32(hw_lradc_ctrl4);
+ mxs_reg_32(hw_lradc_treshold0);
+ mxs_reg_32(hw_lradc_treshold1);
+ mxs_reg_32(hw_lradc_version);
+};
+#endif
+
+#define LRADC_CTRL0_SFTRST (1 << 31)
+#define LRADC_CTRL0_CLKGATE (1 << 30)
+#define LRADC_CTRL0_ONCHIP_GROUNDREF (1 << 26)
+#define LRADC_CTRL0_BUTTON1_DETECT_ENABLE (1 << 25)
+#define LRADC_CTRL0_BUTTON0_DETECT_ENABLE (1 << 24)
+#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23)
+#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22)
+#define LRADC_CTRL0_YNLRSW (1 << 21)
+#define LRADC_CTRL0_YPLLSW_MASK (0x3 << 19)
+#define LRADC_CTRL0_YPLLSW_OFFSET 19
+#define LRADC_CTRL0_XNURSW_MASK (0x3 << 17)
+#define LRADC_CTRL0_XNURSW_OFFSET 17
+#define LRADC_CTRL0_XPULSW (1 << 16)
+#define LRADC_CTRL0_SCHEDULE_MASK 0xff
+#define LRADC_CTRL0_SCHEDULE_OFFSET 0
+
+#define LRADC_CTRL1_BUTTON1_DETECT_IRQ_EN (1 << 28)
+#define LRADC_CTRL1_BUTTON0_DETECT_IRQ_EN (1 << 27)
+#define LRADC_CTRL1_THRESHOLD1_DETECT_IRQ_EN (1 << 26)
+#define LRADC_CTRL1_THRESHOLD0_DETECT_IRQ_EN (1 << 25)
+#define LRADC_CTRL1_TOUCH_DETECT_IRQ_EN (1 << 24)
+#define LRADC_CTRL1_LRADC7_IRQ_EN (1 << 23)
+#define LRADC_CTRL1_LRADC6_IRQ_EN (1 << 22)
+#define LRADC_CTRL1_LRADC5_IRQ_EN (1 << 21)
+#define LRADC_CTRL1_LRADC4_IRQ_EN (1 << 20)
+#define LRADC_CTRL1_LRADC3_IRQ_EN (1 << 19)
+#define LRADC_CTRL1_LRADC2_IRQ_EN (1 << 18)
+#define LRADC_CTRL1_LRADC1_IRQ_EN (1 << 17)
+#define LRADC_CTRL1_LRADC0_IRQ_EN (1 << 16)
+#define LRADC_CTRL1_BUTTON1_DETECT_IRQ (1 << 12)
+#define LRADC_CTRL1_BUTTON0_DETECT_IRQ (1 << 11)
+#define LRADC_CTRL1_THRESHOLD1_DETECT_IRQ (1 << 10)
+#define LRADC_CTRL1_THRESHOLD0_DETECT_IRQ (1 << 9)
+#define LRADC_CTRL1_TOUCH_DETECT_IRQ (1 << 8)
+#define LRADC_CTRL1_LRADC7_IRQ (1 << 7)
+#define LRADC_CTRL1_LRADC6_IRQ (1 << 6)
+#define LRADC_CTRL1_LRADC5_IRQ (1 << 5)
+#define LRADC_CTRL1_LRADC4_IRQ (1 << 4)
+#define LRADC_CTRL1_LRADC3_IRQ (1 << 3)
+#define LRADC_CTRL1_LRADC2_IRQ (1 << 2)
+#define LRADC_CTRL1_LRADC1_IRQ (1 << 1)
+#define LRADC_CTRL1_LRADC0_IRQ (1 << 0)
+
+#define LRADC_CTRL2_DIVIDE_BY_TWO_MASK (0xff << 24)
+#define LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET 24
+#define LRADC_CTRL2_TEMPSENSE_PWD (1 << 15)
+#define LRADC_CTRL2_VTHSENSE_MASK (0x3 << 13)
+#define LRADC_CTRL2_VTHSENSE_OFFSET 13
+#define LRADC_CTRL2_DISABLE_MUXAMP_BYPASS (1 << 12)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE1 (1 << 9)
+#define LRADC_CTRL2_TEMP_SENSOR_IENABLE0 (1 << 8)
+#define LRADC_CTRL2_TEMP_ISRC1_MASK (0xf << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_OFFSET 4
+#define LRADC_CTRL2_TEMP_ISRC1_300 (0xf << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_280 (0xe << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_260 (0xd << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_240 (0xc << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_220 (0xb << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_200 (0xa << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_180 (0x9 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_160 (0x8 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_140 (0x7 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_120 (0x6 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_100 (0x5 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_80 (0x4 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_60 (0x3 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_40 (0x2 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_20 (0x1 << 4)
+#define LRADC_CTRL2_TEMP_ISRC1_ZERO (0x0 << 4)
+#define LRADC_CTRL2_TEMP_ISRC0_MASK (0xf << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_OFFSET 0
+#define LRADC_CTRL2_TEMP_ISRC0_300 (0xf << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_280 (0xe << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_260 (0xd << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_240 (0xc << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_220 (0xb << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_200 (0xa << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_180 (0x9 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_160 (0x8 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_140 (0x7 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_120 (0x6 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_100 (0x5 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_80 (0x4 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_60 (0x3 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_40 (0x2 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_20 (0x1 << 0)
+#define LRADC_CTRL2_TEMP_ISRC0_ZERO (0x0 << 0)
+
+#define LRADC_CTRL3_DISCARD_MASK (0x3 << 24)
+#define LRADC_CTRL3_DISCARD_OFFSET 24
+#define LRADC_CTRL3_DISCARD_1_SAMPLE (0x1 << 24)
+#define LRADC_CTRL3_DISCARD_2_SAMPLES (0x2 << 24)
+#define LRADC_CTRL3_DISCARD_3_SAMPLES (0x3 << 24)
+#define LRADC_CTRL3_FORCE_ANALOG_PWUP (1 << 23)
+#define LRADC_CTRL3_FORCE_ANALOG_PWDN (1 << 22)
+#define LRADC_CTRL3_CYCLE_TIME_MASK (0x3 << 8)
+#define LRADC_CTRL3_CYCLE_TIME_OFFSET 8
+#define LRADC_CTRL3_CYCLE_TIME_6MHZ (0x0 << 8)
+#define LRADC_CTRL3_CYCLE_TIME_4MHZ (0x1 << 8)
+#define LRADC_CTRL3_CYCLE_TIME_3MHZ (0x2 << 8)
+#define LRADC_CTRL3_CYCLE_TIME_2MHZ (0x3 << 8)
+#define LRADC_CTRL3_HIGH_TIME_MASK (0x3 << 4)
+#define LRADC_CTRL3_HIGH_TIME_OFFSET 4
+#define LRADC_CTRL3_HIGH_TIME_42NS (0x0 << 4)
+#define LRADC_CTRL3_HIGH_TIME_83NS (0x1 << 4)
+#define LRADC_CTRL3_HIGH_TIME_125NS (0x2 << 4)
+#define LRADC_CTRL3_HIGH_TIME_250NS (0x3 << 4)
+#define LRADC_CTRL3_DELAY_CLOCK (1 << 1)
+#define LRADC_CTRL3_INVERT_CLOCK (1 << 0)
+
+#define LRADC_STATUS_BUTTON1_PRESENT (1 << 28)
+#define LRADC_STATUS_BUTTON0_PRESENT (1 << 27)
+#define LRADC_STATUS_TEMP1_PRESENT (1 << 26)
+#define LRADC_STATUS_TEMP0_PRESENT (1 << 25)
+#define LRADC_STATUS_TOUCH_PANEL_PRESENT (1 << 24)
+#define LRADC_STATUS_CHANNEL7_PRESENT (1 << 23)
+#define LRADC_STATUS_CHANNEL6_PRESENT (1 << 22)
+#define LRADC_STATUS_CHANNEL5_PRESENT (1 << 21)
+#define LRADC_STATUS_CHANNEL4_PRESENT (1 << 20)
+#define LRADC_STATUS_CHANNEL3_PRESENT (1 << 19)
+#define LRADC_STATUS_CHANNEL2_PRESENT (1 << 18)
+#define LRADC_STATUS_CHANNEL1_PRESENT (1 << 17)
+#define LRADC_STATUS_CHANNEL0_PRESENT (1 << 16)
+#define LRADC_STATUS_BUTTON1_DETECT_RAW (1 << 2)
+#define LRADC_STATUS_BUTTON0_DETECT_RAW (1 << 1)
+#define LRADC_STATUS_TOUCH_DETECT_RAW (1 << 0)
+
+#define LRADC_CH_TOGGLE (1 << 31)
+#define LRADC_CH7_TESTMODE_TOGGLE (1 << 30)
+#define LRADC_CH_ACCUMULATE (1 << 29)
+#define LRADC_CH_NUM_SAMPLES_MASK (0x1f << 24)
+#define LRADC_CH_NUM_SAMPLES_OFFSET 24
+#define LRADC_CH_VALUE_MASK 0x3ffff
+#define LRADC_CH_VALUE_OFFSET 0
+
+#define LRADC_DELAY_TRIGGER_LRADCS_MASK (0xff << 24)
+#define LRADC_DELAY_TRIGGER_LRADCS_OFFSET 24
+#define LRADC_DELAY_KICK (1 << 20)
+#define LRADC_DELAY_TRIGGER_DELAYS_MASK (0xf << 16)
+#define LRADC_DELAY_TRIGGER_DELAYS_OFFSET 16
+#define LRADC_DELAY_LOOP_COUNT_MASK (0x1f << 11)
+#define LRADC_DELAY_LOOP_COUNT_OFFSET 11
+#define LRADC_DELAY_DELAY_MASK 0x7ff
+#define LRADC_DELAY_DELAY_OFFSET 0
+
+#define LRADC_DEBUG0_READONLY_MASK (0xffff << 16)
+#define LRADC_DEBUG0_READONLY_OFFSET 16
+#define LRADC_DEBUG0_STATE_MASK (0xfff << 0)
+#define LRADC_DEBUG0_STATE_OFFSET 0
+
+#define LRADC_DEBUG1_REQUEST_MASK (0xff << 16)
+#define LRADC_DEBUG1_REQUEST_OFFSET 16
+#define LRADC_DEBUG1_TESTMODE_COUNT_MASK (0x1f << 8)
+#define LRADC_DEBUG1_TESTMODE_COUNT_OFFSET 8
+#define LRADC_DEBUG1_TESTMODE6 (1 << 2)
+#define LRADC_DEBUG1_TESTMODE5 (1 << 1)
+#define LRADC_DEBUG1_TESTMODE (1 << 0)
+
+#define LRADC_CONVERSION_AUTOMATIC (1 << 20)
+#define LRADC_CONVERSION_SCALE_FACTOR_MASK (0x3 << 16)
+#define LRADC_CONVERSION_SCALE_FACTOR_OFFSET 16
+#define LRADC_CONVERSION_SCALE_FACTOR_NIMH (0x0 << 16)
+#define LRADC_CONVERSION_SCALE_FACTOR_DUAL_NIMH (0x1 << 16)
+#define LRADC_CONVERSION_SCALE_FACTOR_LI_ION (0x2 << 16)
+#define LRADC_CONVERSION_SCALE_FACTOR_ALT_LI_ION (0x3 << 16)
+#define LRADC_CONVERSION_SCALED_BATT_VOLTAGE_MASK 0x3ff
+#define LRADC_CONVERSION_SCALED_BATT_VOLTAGE_OFFSET 0
+
+#define LRADC_CTRL4_LRADC7SELECT_MASK (0xf << 28)
+#define LRADC_CTRL4_LRADC7SELECT_OFFSET 28
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL0 (0x0 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL1 (0x1 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL2 (0x2 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL3 (0x3 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL4 (0x4 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL5 (0x5 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL6 (0x6 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL7 (0x7 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL8 (0x8 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL9 (0x9 << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL10 (0xa << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL11 (0xb << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL12 (0xc << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL13 (0xd << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL14 (0xe << 28)
+#define LRADC_CTRL4_LRADC7SELECT_CHANNEL15 (0xf << 28)
+#define LRADC_CTRL4_LRADC6SELECT_MASK (0xf << 24)
+#define LRADC_CTRL4_LRADC6SELECT_OFFSET 24
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL0 (0x0 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL1 (0x1 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL2 (0x2 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL3 (0x3 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL4 (0x4 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL5 (0x5 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL6 (0x6 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL7 (0x7 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL8 (0x8 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL9 (0x9 << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL10 (0xa << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL11 (0xb << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL12 (0xc << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL13 (0xd << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL14 (0xe << 24)
+#define LRADC_CTRL4_LRADC6SELECT_CHANNEL15 (0xf << 24)
+#define LRADC_CTRL4_LRADC5SELECT_MASK (0xf << 20)
+#define LRADC_CTRL4_LRADC5SELECT_OFFSET 20
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL0 (0x0 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL1 (0x1 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL2 (0x2 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL3 (0x3 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL4 (0x4 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL5 (0x5 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL6 (0x6 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL7 (0x7 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL8 (0x8 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL9 (0x9 << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL10 (0xa << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL11 (0xb << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL12 (0xc << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL13 (0xd << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL14 (0xe << 20)
+#define LRADC_CTRL4_LRADC5SELECT_CHANNEL15 (0xf << 20)
+#define LRADC_CTRL4_LRADC4SELECT_MASK (0xf << 16)
+#define LRADC_CTRL4_LRADC4SELECT_OFFSET 16
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL0 (0x0 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL1 (0x1 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL2 (0x2 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL3 (0x3 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL4 (0x4 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL5 (0x5 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL6 (0x6 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL7 (0x7 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL8 (0x8 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL9 (0x9 << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL10 (0xa << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL11 (0xb << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL12 (0xc << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL13 (0xd << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL14 (0xe << 16)
+#define LRADC_CTRL4_LRADC4SELECT_CHANNEL15 (0xf << 16)
+#define LRADC_CTRL4_LRADC3SELECT_MASK (0xf << 12)
+#define LRADC_CTRL4_LRADC3SELECT_OFFSET 12
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL0 (0x0 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL1 (0x1 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL2 (0x2 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL3 (0x3 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL4 (0x4 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL5 (0x5 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL6 (0x6 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL7 (0x7 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL8 (0x8 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL9 (0x9 << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL10 (0xa << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL11 (0xb << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL12 (0xc << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL13 (0xd << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL14 (0xe << 12)
+#define LRADC_CTRL4_LRADC3SELECT_CHANNEL15 (0xf << 12)
+#define LRADC_CTRL4_LRADC2SELECT_MASK (0xf << 8)
+#define LRADC_CTRL4_LRADC2SELECT_OFFSET 8
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL0 (0x0 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL1 (0x1 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL2 (0x2 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL3 (0x3 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL4 (0x4 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL5 (0x5 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL6 (0x6 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL7 (0x7 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL8 (0x8 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL9 (0x9 << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL10 (0xa << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL11 (0xb << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL12 (0xc << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL13 (0xd << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL14 (0xe << 8)
+#define LRADC_CTRL4_LRADC2SELECT_CHANNEL15 (0xf << 8)
+#define LRADC_CTRL4_LRADC1SELECT_MASK (0xf << 4)
+#define LRADC_CTRL4_LRADC1SELECT_OFFSET 4
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL0 (0x0 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL1 (0x1 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL2 (0x2 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL3 (0x3 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL4 (0x4 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL5 (0x5 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL6 (0x6 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL7 (0x7 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL8 (0x8 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL9 (0x9 << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL10 (0xa << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL11 (0xb << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL12 (0xc << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL13 (0xd << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL14 (0xe << 4)
+#define LRADC_CTRL4_LRADC1SELECT_CHANNEL15 (0xf << 4)
+#define LRADC_CTRL4_LRADC0SELECT_MASK 0xf
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL0 (0x0 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL1 (0x1 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL2 (0x2 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL3 (0x3 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL4 (0x4 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL5 (0x5 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL6 (0x6 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL7 (0x7 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL8 (0x8 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL9 (0x9 << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL10 (0xa << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL11 (0xb << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL12 (0xc << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL13 (0xd << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL14 (0xe << 0)
+#define LRADC_CTRL4_LRADC0SELECT_CHANNEL15 (0xf << 0)
+
+#define LRADC_THRESHOLD_ENABLE (1 << 24)
+#define LRADC_THRESHOLD_BATTCHRG_DISABLE (1 << 23)
+#define LRADC_THRESHOLD_CHANNEL_SEL_MASK (0x7 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_OFFSET 20
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL0 (0x0 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL1 (0x1 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL2 (0x2 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL3 (0x3 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL4 (0x4 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL5 (0x5 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL6 (0x6 << 20)
+#define LRADC_THRESHOLD_CHANNEL_SEL_CHANNEL7 (0x7 << 20)
+#define LRADC_THRESHOLD_SETTING_MASK (0x3 << 18)
+#define LRADC_THRESHOLD_SETTING_OFFSET 18
+#define LRADC_THRESHOLD_SETTING_NO_COMPARE (0x0 << 18)
+#define LRADC_THRESHOLD_SETTING_DETECT_LOW (0x1 << 18)
+#define LRADC_THRESHOLD_SETTING_DETECT_HIGH (0x2 << 18)
+#define LRADC_THRESHOLD_SETTING_RESERVED (0x3 << 18)
+#define LRADC_THRESHOLD_VALUE_MASK 0x3ffff
+#define LRADC_THRESHOLD_VALUE_OFFSET 0
+
+#define LRADC_VERSION_MAJOR_MASK (0xff << 24)
+#define LRADC_VERSION_MAJOR_OFFSET 24
+#define LRADC_VERSION_MINOR_MASK (0xff << 16)
+#define LRADC_VERSION_MINOR_OFFSET 16
+#define LRADC_VERSION_STEP_MASK 0xffff
+#define LRADC_VERSION_STEP_OFFSET 0
+
+#endif /* __MX28_REGS_LRADC_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/regs-power-mx28.h b/arch/arm/mach-mxs/include/mach/regs-power-mx28.h
new file mode 100644
index 0000000000..7b7349662b
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/regs-power-mx28.h
@@ -0,0 +1,408 @@
+/*
+ * Freescale i.MX28 Power Controller Register Definitions
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX28_REGS_POWER_H__
+#define __MX28_REGS_POWER_H__
+
+#include <mach/regs-common.h>
+
+#ifndef __ASSEMBLY__
+struct mxs_power_regs {
+ mxs_reg_32(hw_power_ctrl)
+ mxs_reg_32(hw_power_5vctrl)
+ mxs_reg_32(hw_power_minpwr)
+ mxs_reg_32(hw_power_charge)
+ uint32_t hw_power_vdddctrl;
+ uint32_t reserved_vddd[3];
+ uint32_t hw_power_vddactrl;
+ uint32_t reserved_vdda[3];
+ uint32_t hw_power_vddioctrl;
+ uint32_t reserved_vddio[3];
+ uint32_t hw_power_vddmemctrl;
+ uint32_t reserved_vddmem[3];
+ uint32_t hw_power_dcdc4p2;
+ uint32_t reserved_dcdc4p2[3];
+ uint32_t hw_power_misc;
+ uint32_t reserved_misc[3];
+ uint32_t hw_power_dclimits;
+ uint32_t reserved_dclimits[3];
+ mxs_reg_32(hw_power_loopctrl)
+ uint32_t hw_power_sts;
+ uint32_t reserved_sts[3];
+ mxs_reg_32(hw_power_speed)
+ uint32_t hw_power_battmonitor;
+ uint32_t reserved_battmonitor[3];
+
+ uint32_t reserved[4];
+
+ mxs_reg_32(hw_power_reset)
+};
+#endif
+
+#define MX23_POWER_CTRL_CLKGATE (1 << 30)
+#define POWER_CTRL_PSWITCH_MID_TRAN (1 << 27)
+#define POWER_CTRL_DCDC4P2_BO_IRQ (1 << 24)
+#define POWER_CTRL_ENIRQ_DCDC4P2_BO (1 << 23)
+#define POWER_CTRL_VDD5V_DROOP_IRQ (1 << 22)
+#define POWER_CTRL_ENIRQ_VDD5V_DROOP (1 << 21)
+#define POWER_CTRL_PSWITCH_IRQ (1 << 20)
+#define POWER_CTRL_PSWITCH_IRQ_SRC (1 << 19)
+#define POWER_CTRL_POLARITY_PSWITCH (1 << 18)
+#define POWER_CTRL_ENIRQ_PSWITCH (1 << 17)
+#define POWER_CTRL_POLARITY_DC_OK (1 << 16)
+#define POWER_CTRL_DC_OK_IRQ (1 << 15)
+#define POWER_CTRL_ENIRQ_DC_OK (1 << 14)
+#define POWER_CTRL_BATT_BO_IRQ (1 << 13)
+#define POWER_CTRL_ENIRQ_BATT_BO (1 << 12)
+#define POWER_CTRL_VDDIO_BO_IRQ (1 << 11)
+#define POWER_CTRL_ENIRQ_VDDIO_BO (1 << 10)
+#define POWER_CTRL_VDDA_BO_IRQ (1 << 9)
+#define POWER_CTRL_ENIRQ_VDDA_BO (1 << 8)
+#define POWER_CTRL_VDDD_BO_IRQ (1 << 7)
+#define POWER_CTRL_ENIRQ_VDDD_BO (1 << 6)
+#define POWER_CTRL_POLARITY_VBUSVALID (1 << 5)
+#define POWER_CTRL_VBUS_VALID_IRQ (1 << 4)
+#define POWER_CTRL_ENIRQ_VBUS_VALID (1 << 3)
+#define POWER_CTRL_POLARITY_VDD5V_GT_VDDIO (1 << 2)
+#define POWER_CTRL_VDD5V_GT_VDDIO_IRQ (1 << 1)
+#define POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO (1 << 0)
+
+#define MX28_POWER_5VCTRL_VBUSDROOP_TRSH_MASK (0x3 << 30)
+#define MX28_POWER_5VCTRL_VBUSDROOP_TRSH_OFFSET 30
+#define MX28_POWER_5VCTRL_VBUSDROOP_TRSH_4V3 (0x0 << 30)
+#define MX28_POWER_5VCTRL_VBUSDROOP_TRSH_4V4 (0x1 << 30)
+#define MX28_POWER_5VCTRL_VBUSDROOP_TRSH_4V5 (0x2 << 30)
+#define MX28_POWER_5VCTRL_VBUSDROOP_TRSH_4V7 (0x3 << 30)
+
+#define MX23_POWER_5VCTRL_VBUSDROOP_TRSH_MASK (0x3 << 28)
+#define MX23_POWER_5VCTRL_VBUSDROOP_TRSH_OFFSET 28
+#define MX23_POWER_5VCTRL_VBUSDROOP_TRSH_4V3 (0x0 << 28)
+#define MX23_POWER_5VCTRL_VBUSDROOP_TRSH_4V4 (0x1 << 28)
+#define MX23_POWER_5VCTRL_VBUSDROOP_TRSH_4V5 (0x2 << 28)
+#define MX23_POWER_5VCTRL_VBUSDROOP_TRSH_4V7 (0x3 << 28)
+
+#define POWER_5VCTRL_HEADROOM_ADJ_MASK (0x7 << 24)
+#define POWER_5VCTRL_HEADROOM_ADJ_OFFSET 24
+#define MX28_POWER_5VCTRL_PWD_CHARGE_4P2_MASK (0x3 << 20)
+#define MX23_POWER_5VCTRL_PWD_CHARGE_4P2_MASK (0x1 << 20)
+#define POWER_5VCTRL_PWD_CHARGE_4P2_OFFSET 20
+#define POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK (0x3f << 12)
+#define POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET 12
+#define POWER_5VCTRL_VBUSVALID_TRSH_MASK (0x7 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_OFFSET 8
+#define POWER_5VCTRL_VBUSVALID_TRSH_2V9 (0x0 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V0 (0x1 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V1 (0x2 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V2 (0x3 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V3 (0x4 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V4 (0x5 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V5 (0x6 << 8)
+#define POWER_5VCTRL_VBUSVALID_TRSH_4V6 (0x7 << 8)
+#define POWER_5VCTRL_PWDN_5VBRNOUT (1 << 7)
+#define POWER_5VCTRL_ENABLE_LINREG_ILIMIT (1 << 6)
+#define POWER_5VCTRL_DCDC_XFER (1 << 5)
+#define POWER_5VCTRL_VBUSVALID_5VDETECT (1 << 4)
+#define POWER_5VCTRL_VBUSVALID_TO_B (1 << 3)
+#define POWER_5VCTRL_ILIMIT_EQ_ZERO (1 << 2)
+#define POWER_5VCTRL_PWRUP_VBUS_CMPS (1 << 1)
+#define POWER_5VCTRL_ENABLE_DCDC (1 << 0)
+
+#define POWER_MINPWR_LOWPWR_4P2 (1 << 14)
+#define MX23_POWER_MINPWR_VDAC_DUMP_CTRL (1 << 13)
+#define POWER_MINPWR_PWD_BO (1 << 12)
+#define POWER_MINPWR_USE_VDDXTAL_VBG (1 << 11)
+#define POWER_MINPWR_PWD_ANA_CMPS (1 << 10)
+#define POWER_MINPWR_ENABLE_OSC (1 << 9)
+#define POWER_MINPWR_SELECT_OSC (1 << 8)
+#define POWER_MINPWR_VBG_OFF (1 << 7)
+#define POWER_MINPWR_DOUBLE_FETS (1 << 6)
+#define POWER_MINPWR_HALFFETS (1 << 5)
+#define POWER_MINPWR_LESSANA_I (1 << 4)
+#define POWER_MINPWR_PWD_XTAL24 (1 << 3)
+#define POWER_MINPWR_DC_STOPCLK (1 << 2)
+#define POWER_MINPWR_EN_DC_PFM (1 << 1)
+#define POWER_MINPWR_DC_HALFCLK (1 << 0)
+
+#define POWER_CHARGE_ADJ_VOLT_MASK (0x7 << 24)
+#define POWER_CHARGE_ADJ_VOLT_OFFSET 24
+#define POWER_CHARGE_ADJ_VOLT_M025P (0x1 << 24)
+#define POWER_CHARGE_ADJ_VOLT_P050P (0x2 << 24)
+#define POWER_CHARGE_ADJ_VOLT_M075P (0x3 << 24)
+#define POWER_CHARGE_ADJ_VOLT_P025P (0x4 << 24)
+#define POWER_CHARGE_ADJ_VOLT_M050P (0x5 << 24)
+#define POWER_CHARGE_ADJ_VOLT_P075P (0x6 << 24)
+#define POWER_CHARGE_ADJ_VOLT_M100P (0x7 << 24)
+#define POWER_CHARGE_ENABLE_LOAD (1 << 22)
+#define MX23_POWER_CHARGE_ENABLE_CHARGER_RESISTORS (1 << 21)
+#define POWER_CHARGE_ENABLE_FAULT_DETECT (1 << 20)
+#define POWER_CHARGE_CHRG_STS_OFF (1 << 19)
+#define MX28_POWER_CHARGE_LIION_4P1 (1 << 18)
+#define MX23_POWER_CHARGE_USE_EXTERN_R (1 << 17)
+#define POWER_CHARGE_PWD_BATTCHRG (1 << 16)
+#define MX28_POWER_CHARGE_ENABLE_CHARGER_USB1 (1 << 13)
+#define MX28_POWER_CHARGE_ENABLE_CHARGER_USB0 (1 << 12)
+#define POWER_CHARGE_STOP_ILIMIT_MASK (0xf << 8)
+#define POWER_CHARGE_STOP_ILIMIT_OFFSET 8
+#define POWER_CHARGE_STOP_ILIMIT_10MA (0x1 << 8)
+#define POWER_CHARGE_STOP_ILIMIT_20MA (0x2 << 8)
+#define POWER_CHARGE_STOP_ILIMIT_50MA (0x4 << 8)
+#define POWER_CHARGE_STOP_ILIMIT_100MA (0x8 << 8)
+#define POWER_CHARGE_BATTCHRG_I_MASK 0x3f
+#define POWER_CHARGE_BATTCHRG_I_OFFSET 0
+#define POWER_CHARGE_BATTCHRG_I_10MA 0x01
+#define POWER_CHARGE_BATTCHRG_I_20MA 0x02
+#define POWER_CHARGE_BATTCHRG_I_50MA 0x04
+#define POWER_CHARGE_BATTCHRG_I_100MA 0x08
+#define POWER_CHARGE_BATTCHRG_I_200MA 0x10
+#define POWER_CHARGE_BATTCHRG_I_400MA 0x20
+
+#define POWER_VDDDCTRL_ADJTN_MASK (0xf << 28)
+#define POWER_VDDDCTRL_ADJTN_OFFSET 28
+#define POWER_VDDDCTRL_PWDN_BRNOUT (1 << 23)
+#define POWER_VDDDCTRL_DISABLE_STEPPING (1 << 22)
+#define POWER_VDDDCTRL_ENABLE_LINREG (1 << 21)
+#define POWER_VDDDCTRL_DISABLE_FET (1 << 20)
+#define POWER_VDDDCTRL_LINREG_OFFSET_MASK (0x3 << 16)
+#define POWER_VDDDCTRL_LINREG_OFFSET_OFFSET 16
+#define POWER_VDDDCTRL_LINREG_OFFSET_0STEPS (0x0 << 16)
+#define POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_ABOVE (0x1 << 16)
+#define POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW (0x2 << 16)
+#define POWER_VDDDCTRL_LINREG_OFFSET_2STEPS_BELOW (0x3 << 16)
+#define POWER_VDDDCTRL_BO_OFFSET_MASK (0x7 << 8)
+#define POWER_VDDDCTRL_BO_OFFSET_OFFSET 8
+#define POWER_VDDDCTRL_TRG_MASK 0x1f
+#define POWER_VDDDCTRL_TRG_OFFSET 0
+
+#define POWER_VDDACTRL_PWDN_BRNOUT (1 << 19)
+#define POWER_VDDACTRL_DISABLE_STEPPING (1 << 18)
+#define POWER_VDDACTRL_ENABLE_LINREG (1 << 17)
+#define POWER_VDDACTRL_DISABLE_FET (1 << 16)
+#define POWER_VDDACTRL_LINREG_OFFSET_MASK (0x3 << 12)
+#define POWER_VDDACTRL_LINREG_OFFSET_OFFSET 12
+#define POWER_VDDACTRL_LINREG_OFFSET_0STEPS (0x0 << 12)
+#define POWER_VDDACTRL_LINREG_OFFSET_1STEPS_ABOVE (0x1 << 12)
+#define POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW (0x2 << 12)
+#define POWER_VDDACTRL_LINREG_OFFSET_2STEPS_BELOW (0x3 << 12)
+#define POWER_VDDACTRL_BO_OFFSET_MASK (0x7 << 8)
+#define POWER_VDDACTRL_BO_OFFSET_OFFSET 8
+#define POWER_VDDACTRL_TRG_MASK 0x1f
+#define POWER_VDDACTRL_TRG_OFFSET 0
+
+#define POWER_VDDIOCTRL_ADJTN_MASK (0xf << 20)
+#define POWER_VDDIOCTRL_ADJTN_OFFSET 20
+#define POWER_VDDIOCTRL_PWDN_BRNOUT (1 << 18)
+#define POWER_VDDIOCTRL_DISABLE_STEPPING (1 << 17)
+#define POWER_VDDIOCTRL_DISABLE_FET (1 << 16)
+#define POWER_VDDIOCTRL_LINREG_OFFSET_MASK (0x3 << 12)
+#define POWER_VDDIOCTRL_LINREG_OFFSET_OFFSET 12
+#define POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS (0x0 << 12)
+#define POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_ABOVE (0x1 << 12)
+#define POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW (0x2 << 12)
+#define POWER_VDDIOCTRL_LINREG_OFFSET_2STEPS_BELOW (0x3 << 12)
+#define POWER_VDDIOCTRL_BO_OFFSET_MASK (0x7 << 8)
+#define POWER_VDDIOCTRL_BO_OFFSET_OFFSET 8
+#define POWER_VDDIOCTRL_TRG_MASK 0x1f
+#define POWER_VDDIOCTRL_TRG_OFFSET 0
+
+#define POWER_VDDMEMCTRL_PULLDOWN_ACTIVE (1 << 10)
+#define POWER_VDDMEMCTRL_ENABLE_ILIMIT (1 << 9)
+#define POWER_VDDMEMCTRL_ENABLE_LINREG (1 << 8)
+#define MX28_POWER_VDDMEMCTRL_BO_OFFSET_MASK (0x7 << 5)
+#define MX28_POWER_VDDMEMCTRL_BO_OFFSET_OFFSET 5
+#define POWER_VDDMEMCTRL_TRG_MASK 0x1f
+#define POWER_VDDMEMCTRL_TRG_OFFSET 0
+
+#define POWER_DCDC4P2_DROPOUT_CTRL_MASK (0xf << 28)
+#define POWER_DCDC4P2_DROPOUT_CTRL_OFFSET 28
+#define POWER_DCDC4P2_DROPOUT_CTRL_200MV (0x3 << 30)
+#define POWER_DCDC4P2_DROPOUT_CTRL_100MV (0x2 << 30)
+#define POWER_DCDC4P2_DROPOUT_CTRL_50MV (0x1 << 30)
+#define POWER_DCDC4P2_DROPOUT_CTRL_25MV (0x0 << 30)
+#define POWER_DCDC4P2_DROPOUT_CTRL_SRC_4P2 (0x0 << 28)
+#define POWER_DCDC4P2_DROPOUT_CTRL_SRC_4P2_LT_BATT (0x1 << 28)
+#define POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL (0x2 << 28)
+#define POWER_DCDC4P2_ISTEAL_THRESH_MASK (0x3 << 24)
+#define POWER_DCDC4P2_ISTEAL_THRESH_OFFSET 24
+#define POWER_DCDC4P2_ENABLE_4P2 (1 << 23)
+#define POWER_DCDC4P2_ENABLE_DCDC (1 << 22)
+#define POWER_DCDC4P2_HYST_DIR (1 << 21)
+#define POWER_DCDC4P2_HYST_THRESH (1 << 20)
+#define POWER_DCDC4P2_TRG_MASK (0x7 << 16)
+#define POWER_DCDC4P2_TRG_OFFSET 16
+#define POWER_DCDC4P2_TRG_4V2 (0x0 << 16)
+#define POWER_DCDC4P2_TRG_4V1 (0x1 << 16)
+#define POWER_DCDC4P2_TRG_4V0 (0x2 << 16)
+#define POWER_DCDC4P2_TRG_3V9 (0x3 << 16)
+#define POWER_DCDC4P2_TRG_BATT (0x4 << 16)
+#define POWER_DCDC4P2_BO_MASK (0x1f << 8)
+#define POWER_DCDC4P2_BO_OFFSET 8
+#define POWER_DCDC4P2_CMPTRIP_MASK 0x1f
+#define POWER_DCDC4P2_CMPTRIP_OFFSET 0
+
+#define POWER_MISC_FREQSEL_MASK (0x7 << 4)
+#define POWER_MISC_FREQSEL_OFFSET 4
+#define POWER_MISC_FREQSEL_20MHZ (0x1 << 4)
+#define POWER_MISC_FREQSEL_24MHZ (0x2 << 4)
+#define POWER_MISC_FREQSEL_19MHZ (0x3 << 4)
+#define POWER_MISC_FREQSEL_14MHZ (0x4 << 4)
+#define POWER_MISC_FREQSEL_18MHZ (0x5 << 4)
+#define POWER_MISC_FREQSEL_21MHZ (0x6 << 4)
+#define POWER_MISC_FREQSEL_17MHZ (0x7 << 4)
+#define POWER_MISC_DISABLE_FET_BO_LOGIC (1 << 3)
+#define POWER_MISC_DELAY_TIMING (1 << 2)
+#define POWER_MISC_TEST (1 << 1)
+#define POWER_MISC_SEL_PLLCLK (1 << 0)
+
+#define POWER_DCLIMITS_POSLIMIT_BUCK_MASK (0x7f << 8)
+#define POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET 8
+#define POWER_DCLIMITS_NEGLIMIT_MASK 0x7f
+#define POWER_DCLIMITS_NEGLIMIT_OFFSET 0
+
+#define POWER_LOOPCTRL_TOGGLE_DIF (1 << 20)
+#define POWER_LOOPCTRL_HYST_SIGN (1 << 19)
+#define POWER_LOOPCTRL_EN_CM_HYST (1 << 18)
+#define POWER_LOOPCTRL_EN_DF_HYST (1 << 17)
+#define POWER_LOOPCTRL_CM_HYST_THRESH (1 << 16)
+#define POWER_LOOPCTRL_DF_HYST_THRESH (1 << 15)
+#define POWER_LOOPCTRL_RCSCALE_THRESH (1 << 14)
+#define POWER_LOOPCTRL_EN_RCSCALE_MASK (0x3 << 12)
+#define POWER_LOOPCTRL_EN_RCSCALE_OFFSET 12
+#define POWER_LOOPCTRL_EN_RCSCALE_DIS (0x0 << 12)
+#define POWER_LOOPCTRL_EN_RCSCALE_2X (0x1 << 12)
+#define POWER_LOOPCTRL_EN_RCSCALE_4X (0x2 << 12)
+#define POWER_LOOPCTRL_EN_RCSCALE_8X (0x3 << 12)
+#define POWER_LOOPCTRL_DC_FF_MASK (0x7 << 8)
+#define POWER_LOOPCTRL_DC_FF_OFFSET 8
+#define POWER_LOOPCTRL_DC_R_MASK (0xf << 4)
+#define POWER_LOOPCTRL_DC_R_OFFSET 4
+#define POWER_LOOPCTRL_DC_C_MASK 0x3
+#define POWER_LOOPCTRL_DC_C_OFFSET 0
+#define POWER_LOOPCTRL_DC_C_MAX 0x0
+#define POWER_LOOPCTRL_DC_C_2X 0x1
+#define POWER_LOOPCTRL_DC_C_4X 0x2
+#define POWER_LOOPCTRL_DC_C_MIN 0x3
+
+#define POWER_STS_PWRUP_SOURCE_MASK (0x3f << 24)
+#define POWER_STS_PWRUP_SOURCE_OFFSET 24
+#define POWER_STS_PWRUP_SOURCE_5V (0x20 << 24)
+#define POWER_STS_PWRUP_SOURCE_RTC (0x10 << 24)
+#define POWER_STS_PWRUP_SOURCE_PSWITCH_HIGH (0x02 << 24)
+#define POWER_STS_PWRUP_SOURCE_PSWITCH_MID (0x01 << 24)
+#define POWER_STS_PSWITCH_MASK (0x3 << 20)
+#define POWER_STS_PSWITCH_OFFSET 20
+#define MX28_POWER_STS_THERMAL_WARNING (1 << 19)
+#define MX28_POWER_STS_VDDMEM_BO (1 << 18)
+#define POWER_STS_AVALID0_STATUS (1 << 17)
+#define POWER_STS_BVALID0_STATUS (1 << 16)
+#define POWER_STS_VBUSVALID0_STATUS (1 << 15)
+#define POWER_STS_SESSEND0_STATUS (1 << 14)
+#define POWER_STS_BATT_BO (1 << 13)
+#define POWER_STS_VDD5V_FAULT (1 << 12)
+#define POWER_STS_CHRGSTS (1 << 11)
+#define POWER_STS_DCDC_4P2_BO (1 << 10)
+#define POWER_STS_DC_OK (1 << 9)
+#define POWER_STS_VDDIO_BO (1 << 8)
+#define POWER_STS_VDDA_BO (1 << 7)
+#define POWER_STS_VDDD_BO (1 << 6)
+#define POWER_STS_VDD5V_GT_VDDIO (1 << 5)
+#define POWER_STS_VDD5V_DROOP (1 << 4)
+#define POWER_STS_AVALID0 (1 << 3)
+#define POWER_STS_BVALID0 (1 << 2)
+#define POWER_STS_VBUSVALID0 (1 << 1)
+#define POWER_STS_SESSEND0 (1 << 0)
+
+#define MX23_POWER_SPEED_STATUS_MASK (0xff << 16)
+#define MX23_POWER_SPEED_STATUS_OFFSET 16
+#define MX28_POWER_SPEED_STATUS_MASK (0xffff << 8)
+#define MX28_POWER_SPEED_STATUS_OFFSET 8
+#define MX28_POWER_SPEED_STATUS_SEL_MASK (0x3 << 6)
+#define MX28_POWER_SPEED_STATUS_SEL_OFFSET 6
+#define MX28_POWER_SPEED_STATUS_SEL_DCDC_STAT (0x0 << 6)
+#define MX28_POWER_SPEED_STATUS_SEL_CORE_STAT (0x1 << 6)
+#define MX28_POWER_SPEED_STATUS_SEL_ARM_STAT (0x2 << 6)
+#define POWER_SPEED_CTRL_MASK 0x3
+#define POWER_SPEED_CTRL_OFFSET 0
+#define POWER_SPEED_CTRL_SS_OFF 0x0
+#define POWER_SPEED_CTRL_SS_ON 0x1
+#define POWER_SPEED_CTRL_SS_ENABLE 0x3
+
+#define POWER_BATTMONITOR_BATT_VAL_MASK (0x3ff << 16)
+#define POWER_BATTMONITOR_BATT_VAL_OFFSET 16
+#define MX28_POWER_BATTMONITOR_PWDN_BATTBRNOUT_5VDETECT_EN (1 << 11)
+#define POWER_BATTMONITOR_EN_BATADJ (1 << 10)
+#define POWER_BATTMONITOR_PWDN_BATTBRNOUT (1 << 9)
+#define POWER_BATTMONITOR_BRWNOUT_PWD (1 << 8)
+#define POWER_BATTMONITOR_BRWNOUT_LVL_MASK 0x1f
+#define POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET 0
+
+#define POWER_RESET_UNLOCK_MASK (0xffff << 16)
+#define POWER_RESET_UNLOCK_OFFSET 16
+#define POWER_RESET_UNLOCK_KEY (0x3e77 << 16)
+#define MX28_POWER_RESET_FASTFALL_PSWITCH_OFF (1 << 2)
+#define POWER_RESET_PWD_OFF (1 << 1)
+#define POWER_RESET_PWD (1 << 0)
+
+#define POWER_DEBUG_VBUSVALIDPIOLOCK (1 << 3)
+#define POWER_DEBUG_AVALIDPIOLOCK (1 << 2)
+#define POWER_DEBUG_BVALIDPIOLOCK (1 << 1)
+#define POWER_DEBUG_SESSENDPIOLOCK (1 << 0)
+
+#define MX28_POWER_THERMAL_TEST (1 << 8)
+#define MX28_POWER_THERMAL_PWD (1 << 7)
+#define MX28_POWER_THERMAL_LOW_POWER (1 << 6)
+#define MX28_POWER_THERMAL_OFFSET_ADJ_MASK (0x3 << 4)
+#define MX28_POWER_THERMAL_OFFSET_ADJ_OFFSET 4
+#define MX28_POWER_THERMAL_OFFSET_ADJ_ENABLE (1 << 3)
+#define MX28_POWER_THERMAL_TEMP_THRESHOLD_MASK 0x7
+#define MX28_POWER_THERMAL_TEMP_THRESHOLD_OFFSET 0
+
+#define MX28_POWER_USB1CTRL_AVALID1 (1 << 3)
+#define MX28_POWER_USB1CTRL_BVALID1 (1 << 2)
+#define MX28_POWER_USB1CTRL_VBUSVALID1 (1 << 1)
+#define MX28_POWER_USB1CTRL_SESSEND1 (1 << 0)
+
+#define POWER_SPECIAL_TEST_MASK 0xffffffff
+#define POWER_SPECIAL_TEST_OFFSET 0
+
+#define POWER_VERSION_MAJOR_MASK (0xff << 24)
+#define POWER_VERSION_MAJOR_OFFSET 24
+#define POWER_VERSION_MINOR_MASK (0xff << 16)
+#define POWER_VERSION_MINOR_OFFSET 16
+#define POWER_VERSION_STEP_MASK 0xffff
+#define POWER_VERSION_STEP_OFFSET 0
+
+#define MX28_POWER_ANACLKCTRL_CLKGATE_0 (1 << 31)
+#define MX28_POWER_ANACLKCTRL_OUTDIV_MASK (0x7 << 28)
+#define MX28_POWER_ANACLKCTRL_OUTDIV_OFFSET 28
+#define MX28_POWER_ANACLKCTRL_INVERT_OUTCLK (1 << 27)
+#define MX28_POWER_ANACLKCTRL_CLKGATE_I (1 << 26)
+#define MX28_POWER_ANACLKCTRL_DITHER_OFF (1 << 10)
+#define MX28_POWER_ANACLKCTRL_SLOW_DITHER (1 << 9)
+#define MX28_POWER_ANACLKCTRL_INVERT_INCLK (1 << 8)
+#define MX28_POWER_ANACLKCTRL_INCLK_SHIFT_MASK (0x3 << 4)
+#define MX28_POWER_ANACLKCTRL_INCLK_SHIFT_OFFSET 4
+#define MX28_POWER_ANACLKCTRL_INDIV_MASK 0x7
+#define MX28_POWER_ANACLKCTRL_INDIV_OFFSET 0
+
+#define MX28_POWER_REFCTRL_FASTSETTLING (1 << 26)
+#define MX28_POWER_REFCTRL_RAISE_REF (1 << 25)
+#define MX28_POWER_REFCTRL_XTAL_BGR_BIAS (1 << 24)
+#define MX28_POWER_REFCTRL_VBG_ADJ_MASK (0x7 << 20)
+#define MX28_POWER_REFCTRL_VBG_ADJ_OFFSET 20
+#define MX28_POWER_REFCTRL_LOW_PWR (1 << 19)
+#define MX28_POWER_REFCTRL_BIAS_CTRL_MASK (0x3 << 16)
+#define MX28_POWER_REFCTRL_BIAS_CTRL_OFFSET 16
+#define MX28_POWER_REFCTRL_VDDXTAL_TO_VDDD (1 << 14)
+#define MX28_POWER_REFCTRL_ADJ_ANA (1 << 13)
+#define MX28_POWER_REFCTRL_ADJ_VAG (1 << 12)
+#define MX28_POWER_REFCTRL_ANA_REFVAL_MASK (0xf << 8)
+#define MX28_POWER_REFCTRL_ANA_REFVAL_OFFSET 8
+#define MX28_POWER_REFCTRL_VAG_VAL_MASK (0xf << 4)
+#define MX28_POWER_REFCTRL_VAG_VAL_OFFSET 4
+
+#endif /* __MX28_REGS_POWER_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/regs-rtc.h b/arch/arm/mach-mxs/include/mach/regs-rtc.h
new file mode 100644
index 0000000000..bd8fdad4f7
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/regs-rtc.h
@@ -0,0 +1,134 @@
+/*
+ * Freescale i.MX28 RTC Register Definitions
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MX28_REGS_RTC_H__
+#define __MX28_REGS_RTC_H__
+
+#include <mach/regs-common.h>
+
+#ifndef __ASSEMBLY__
+struct mxs_rtc_regs {
+ mxs_reg_32(hw_rtc_ctrl)
+ mxs_reg_32(hw_rtc_stat)
+ mxs_reg_32(hw_rtc_milliseconds)
+ mxs_reg_32(hw_rtc_seconds)
+ mxs_reg_32(hw_rtc_rtc_alarm)
+ mxs_reg_32(hw_rtc_watchdog)
+ mxs_reg_32(hw_rtc_persistent0)
+ mxs_reg_32(hw_rtc_persistent1)
+ mxs_reg_32(hw_rtc_persistent2)
+ mxs_reg_32(hw_rtc_persistent3)
+ mxs_reg_32(hw_rtc_persistent4)
+ mxs_reg_32(hw_rtc_persistent5)
+ mxs_reg_32(hw_rtc_debug)
+ mxs_reg_32(hw_rtc_version)
+};
+#endif
+
+#define RTC_CTRL_SFTRST (1 << 31)
+#define RTC_CTRL_CLKGATE (1 << 30)
+#define RTC_CTRL_SUPPRESS_COPY2ANALOG (1 << 6)
+#define RTC_CTRL_FORCE_UPDATE (1 << 5)
+#define RTC_CTRL_WATCHDOGEN (1 << 4)
+#define RTC_CTRL_ONEMSEC_IRQ (1 << 3)
+#define RTC_CTRL_ALARM_IRQ (1 << 2)
+#define RTC_CTRL_ONEMSEC_IRQ_EN (1 << 1)
+#define RTC_CTRL_ALARM_IRQ_EN (1 << 0)
+
+#define RTC_STAT_RTC_PRESENT (1 << 31)
+#define RTC_STAT_ALARM_PRESENT (1 << 30)
+#define RTC_STAT_WATCHDOG_PRESENT (1 << 29)
+#define RTC_STAT_XTAL32000_PRESENT (1 << 28)
+#define RTC_STAT_XTAL32768_PRESENT (1 << 27)
+#define RTC_STAT_STALE_REGS_MASK (0xff << 16)
+#define RTC_STAT_STALE_REGS_OFFSET 16
+#define RTC_STAT_NEW_REGS_MASK (0xff << 8)
+#define RTC_STAT_NEW_REGS_OFFSET 8
+
+#define RTC_MILLISECONDS_COUNT_MASK 0xffffffff
+#define RTC_MILLISECONDS_COUNT_OFFSET 0
+
+#define RTC_SECONDS_COUNT_MASK 0xffffffff
+#define RTC_SECONDS_COUNT_OFFSET 0
+
+#define RTC_ALARM_VALUE_MASK 0xffffffff
+#define RTC_ALARM_VALUE_OFFSET 0
+
+#define RTC_WATCHDOG_COUNT_MASK 0xffffffff
+#define RTC_WATCHDOG_COUNT_OFFSET 0
+
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_MASK (0xf << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_OFFSET 28
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V83 (0x0 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V78 (0x1 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V73 (0x2 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V68 (0x3 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V62 (0x4 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V57 (0x5 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V52 (0x6 << 28)
+#define RTC_PERSISTENT0_ADJ_POSLIMITBUCK_2V48 (0x7 << 28)
+#define RTC_PERSISTENT0_EXTERNAL_RESET (1 << 21)
+#define RTC_PERSISTENT0_THERMAL_RESET (1 << 20)
+#define RTC_PERSISTENT0_ENABLE_LRADC_PWRUP (1 << 18)
+#define RTC_PERSISTENT0_AUTO_RESTART (1 << 17)
+#define RTC_PERSISTENT0_DISABLE_PSWITCH (1 << 16)
+#define RTC_PERSISTENT0_LOWERBIAS_MASK (0xf << 14)
+#define RTC_PERSISTENT0_LOWERBIAS_OFFSET 14
+#define RTC_PERSISTENT0_LOWERBIAS_NOMINAL (0x0 << 14)
+#define RTC_PERSISTENT0_LOWERBIAS_M25P (0x1 << 14)
+#define RTC_PERSISTENT0_LOWERBIAS_M50P (0x3 << 14)
+#define RTC_PERSISTENT0_DISABLE_XTALOK (1 << 13)
+#define RTC_PERSISTENT0_MSEC_RES_MASK (0x1f << 8)
+#define RTC_PERSISTENT0_MSEC_RES_OFFSET 8
+#define RTC_PERSISTENT0_MSEC_RES_1MS (0x01 << 8)
+#define RTC_PERSISTENT0_MSEC_RES_2MS (0x02 << 8)
+#define RTC_PERSISTENT0_MSEC_RES_4MS (0x04 << 8)
+#define RTC_PERSISTENT0_MSEC_RES_8MS (0x08 << 8)
+#define RTC_PERSISTENT0_MSEC_RES_16MS (0x10 << 8)
+#define RTC_PERSISTENT0_ALARM_WAKE (1 << 7)
+#define RTC_PERSISTENT0_XTAL32_FREQ (1 << 6)
+#define RTC_PERSISTENT0_XTAL32KHZ_PWRUP (1 << 5)
+#define RTC_PERSISTENT0_XTAL24KHZ_PWRUP (1 << 4)
+#define RTC_PERSISTENT0_LCK_SECS (1 << 3)
+#define RTC_PERSISTENT0_ALARM_EN (1 << 2)
+#define RTC_PERSISTENT0_ALARM_WAKE_EN (1 << 1)
+#define RTC_PERSISTENT0_CLOCKSOURCE (1 << 0)
+
+#define RTC_PERSISTENT1_GENERAL_MASK 0xffffffff
+#define RTC_PERSISTENT1_GENERAL_OFFSET 0
+#define RTC_PERSISTENT1_GENERAL_OTG_ALT_ROLE 0x0080
+#define RTC_PERSISTENT1_GENERAL_OTG_HNP 0x0100
+#define RTC_PERSISTENT1_GENERAL_USB_LPM 0x0200
+#define RTC_PERSISTENT1_GENERAL_SKIP_CHECKDISK 0x0400
+#define RTC_PERSISTENT1_GENERAL_USB_BOOT_PLAYER 0x0800
+#define RTC_PERSISTENT1_GENERAL_ENUM_500MA_2X 0x1000
+
+#define RTC_PERSISTENT2_GENERAL_MASK 0xffffffff
+#define RTC_PERSISTENT2_GENERAL_OFFSET 0
+
+#define RTC_PERSISTENT3_GENERAL_MASK 0xffffffff
+#define RTC_PERSISTENT3_GENERAL_OFFSET 0
+
+#define RTC_PERSISTENT4_GENERAL_MASK 0xffffffff
+#define RTC_PERSISTENT4_GENERAL_OFFSET 0
+
+#define RTC_PERSISTENT5_GENERAL_MASK 0xffffffff
+#define RTC_PERSISTENT5_GENERAL_OFFSET 0
+
+#define RTC_DEBUG_WATCHDOG_RESET_MASK (1 << 1)
+#define RTC_DEBUG_WATCHDOG_RESET (1 << 0)
+
+#define RTC_VERSION_MAJOR_MASK (0xff << 24)
+#define RTC_VERSION_MAJOR_OFFSET 24
+#define RTC_VERSION_MINOR_MASK (0xff << 16)
+#define RTC_VERSION_MINOR_OFFSET 16
+#define RTC_VERSION_STEP_MASK 0xffff
+#define RTC_VERSION_STEP_OFFSET 0
+
+#endif /* __MX28_REGS_RTC_H__ */
diff --git a/arch/arm/mach-mxs/lradc-init.c b/arch/arm/mach-mxs/lradc-init.c
new file mode 100644
index 0000000000..682a47530d
--- /dev/null
+++ b/arch/arm/mach-mxs/lradc-init.c
@@ -0,0 +1,70 @@
+/*
+ * Freescale i.MX28 Battery measurement init
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <mach/imx-regs.h>
+#include <mach/regs-lradc.h>
+#include <mach/init.h>
+
+void mxs_lradc_init(void)
+{
+ struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)IMX_LRADC_BASE;
+
+ writel(LRADC_CTRL0_SFTRST, &regs->hw_lradc_ctrl0_clr);
+ writel(LRADC_CTRL0_CLKGATE, &regs->hw_lradc_ctrl0_clr);
+ writel(LRADC_CTRL0_ONCHIP_GROUNDREF, &regs->hw_lradc_ctrl0_clr);
+
+ clrsetbits_le32(&regs->hw_lradc_ctrl3,
+ LRADC_CTRL3_CYCLE_TIME_MASK,
+ LRADC_CTRL3_CYCLE_TIME_6MHZ);
+
+ clrsetbits_le32(&regs->hw_lradc_ctrl4,
+ LRADC_CTRL4_LRADC7SELECT_MASK |
+ LRADC_CTRL4_LRADC6SELECT_MASK,
+ LRADC_CTRL4_LRADC7SELECT_CHANNEL7 |
+ LRADC_CTRL4_LRADC6SELECT_CHANNEL10);
+}
+
+void mxs_lradc_enable_batt_measurement(void)
+{
+ struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)IMX_LRADC_BASE;
+
+ /* Check if the channel is present at all. */
+ if (!(readl(&regs->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT))
+ return;
+
+ writel(LRADC_CTRL1_LRADC7_IRQ_EN, &regs->hw_lradc_ctrl1_clr);
+ writel(LRADC_CTRL1_LRADC7_IRQ, &regs->hw_lradc_ctrl1_clr);
+
+ clrsetbits_le32(&regs->hw_lradc_conversion,
+ LRADC_CONVERSION_SCALE_FACTOR_MASK,
+ LRADC_CONVERSION_SCALE_FACTOR_LI_ION);
+ writel(LRADC_CONVERSION_AUTOMATIC, &regs->hw_lradc_conversion_set);
+
+ /* Configure the channel. */
+ writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
+ &regs->hw_lradc_ctrl2_clr);
+ writel(0xffffffff, &regs->hw_lradc_ch7_clr);
+ clrbits_le32(&regs->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK);
+ writel(LRADC_CH_ACCUMULATE, &regs->hw_lradc_ch7_clr);
+
+ /* Schedule the channel. */
+ writel(1 << 7, &regs->hw_lradc_ctrl0_set);
+
+ /* Start the channel sampling. */
+ writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) |
+ ((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) |
+ 100, &regs->hw_lradc_delay3);
+
+ writel(0xffffffff, &regs->hw_lradc_ch7_clr);
+
+ writel(LRADC_DELAY_KICK, &regs->hw_lradc_delay3_set);
+}
diff --git a/arch/arm/mach-mxs/mem-init.c b/arch/arm/mach-mxs/mem-init.c
new file mode 100644
index 0000000000..9773f94903
--- /dev/null
+++ b/arch/arm/mach-mxs/mem-init.c
@@ -0,0 +1,371 @@
+/*
+ * Freescale i.MX28 RAM init
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * Copyright 2013 Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <config.h>
+#include <io.h>
+#include <mach/imx-regs.h>
+#include <linux/compiler.h>
+
+#include <mach/init.h>
+#include <mach/regs-power-mx28.h>
+#if defined CONFIG_ARCH_IMX23
+# include <mach/regs-clkctrl-mx23.h>
+#endif
+#if defined CONFIG_ARCH_IMX28
+# include <mach/regs-clkctrl-mx28.h>
+#endif
+
+/* 1 second delay should be plenty of time for block reset. */
+#define RESET_MAX_TIMEOUT 1000000
+
+#define MXS_BLOCK_SFTRST (1 << 31)
+#define MXS_BLOCK_CLKGATE (1 << 30)
+
+int mxs_early_wait_mask_set(struct mxs_register_32 *reg, uint32_t mask, unsigned
+ int timeout)
+{
+ while (--timeout) {
+ if ((readl(&reg->reg) & mask) == mask)
+ break;
+ mxs_early_delay(1);
+ }
+
+ return !timeout;
+}
+
+int mxs_early_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned
+ int timeout)
+{
+ while (--timeout) {
+ if ((readl(&reg->reg) & mask) == 0)
+ break;
+ mxs_early_delay(1);
+ }
+
+ return !timeout;
+}
+
+int mxs_early_reset_block(struct mxs_register_32 *reg)
+{
+ /* Clear SFTRST */
+ writel(MXS_BLOCK_SFTRST, &reg->reg_clr);
+
+ if (mxs_early_wait_mask_clr(reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT))
+ return 1;
+
+ /* Clear CLKGATE */
+ writel(MXS_BLOCK_CLKGATE, &reg->reg_clr);
+
+ /* Set SFTRST */
+ writel(MXS_BLOCK_SFTRST, &reg->reg_set);
+
+ /* Wait for CLKGATE being set */
+ if (mxs_early_wait_mask_set(reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT))
+ return 1;
+
+ /* Clear SFTRST */
+ writel(MXS_BLOCK_SFTRST, &reg->reg_clr);
+
+ if (mxs_early_wait_mask_clr(reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT))
+ return 1;
+
+ /* Clear CLKGATE */
+ writel(MXS_BLOCK_CLKGATE, &reg->reg_clr);
+
+ if (mxs_early_wait_mask_clr(reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT))
+ return 1;
+
+ return 0;
+}
+
+uint32_t mx28_dram_vals[] = {
+/*
+ * i.MX28 DDR2 at 200MHz
+ */
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000100, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00010101, 0x01010101,
+ 0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101,
+ 0x00000100, 0x00000100, 0x00000000, 0x00000002,
+ 0x01010000, 0x07080403, 0x06005003, 0x0a0000c8,
+ 0x02009c40, 0x0002030c, 0x0036a609, 0x031a0612,
+ 0x02030202, 0x00c8001c, 0x00000000, 0x00000000,
+ 0x00012100, 0xffff0303, 0x00012100, 0xffff0303,
+ 0x00012100, 0xffff0303, 0x00012100, 0xffff0303,
+ 0x00000003, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000612, 0x01000F02,
+ 0x06120612, 0x00000200, 0x00020007, 0xf4004a27,
+ 0xf4004a27, 0xf4004a27, 0xf4004a27, 0x07000300,
+ 0x07000300, 0x07400300, 0x07400300, 0x00000005,
+ 0x00000000, 0x00000000, 0x01000000, 0x01020408,
+ 0x08040201, 0x000f1133, 0x00000000, 0x00001f04,
+ 0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04,
+ 0x00001f04, 0x00001f04, 0x00001f04, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00010000, 0x00030404,
+ 0x00000003, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x01010000,
+ 0x01000000, 0x03030000, 0x00010303, 0x01020202,
+ 0x00000000, 0x02040303, 0x21002103, 0x00061200,
+ 0x06120612, 0x04420442, 0x04420442, 0x00040004,
+ 0x00040004, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0xffffffff
+};
+
+/*
+ * i.MX23 DDR at 133MHz
+ */
+uint32_t mx23_dram_vals[] = {
+ 0x01010001, 0x00010100, 0x01000101, 0x00000001,
+ 0x00000101, 0x00000000, 0x00010000, 0x01000001,
+ 0x00000000, 0x00000001, 0x07000200, 0x00070202,
+ 0x02020000, 0x04040a01, 0x00000201, 0x02040000,
+ 0x02000000, 0x19000f08, 0x0d0d0000, 0x02021313,
+ 0x02061521, 0x0000000a, 0x00080008, 0x00200020,
+ 0x00200020, 0x00200020, 0x000003f7, 0x00000000,
+ 0x00000000, 0x00000020, 0x00000020, 0x00c80000,
+ 0x000a23cd, 0x000000c8, 0x00006665, 0x00000000,
+ 0x00000101, 0x00040001, 0x00000000, 0x00000000,
+ 0x00010000
+};
+
+static void mx28_initialize_dram_values(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mx28_dram_vals); i++)
+ writel(mx28_dram_vals[i], IMX_SDRAMC_BASE + (4 * i));
+}
+
+static void mx23_initialize_dram_values(void)
+{
+ int i;
+
+ /*
+ * HW_DRAM_CTL27, HW_DRAM_CTL28 and HW_DRAM_CTL35 are not initialized as
+ * per FSL bootlets code.
+ *
+ * mx23 Reference Manual marks HW_DRAM_CTL27 and HW_DRAM_CTL28 as
+ * "reserved".
+ * HW_DRAM_CTL8 is setup as the last element.
+ * So skip the initialization of these HW_DRAM_CTL registers.
+ */
+ for (i = 0; i < ARRAY_SIZE(mx23_dram_vals); i++) {
+ if (i == 8 || i == 27 || i == 28 || i == 35)
+ continue;
+ writel(mx23_dram_vals[i], IMX_SDRAMC_BASE + (4 * i));
+ }
+
+ /*
+ * Enable tRAS lockout in HW_DRAM_CTL08 ; it must be the last
+ * element to be set
+ */
+ writel((1 << 24), IMX_SDRAMC_BASE + (4 * 8));
+}
+
+void mxs_mem_init_clock(unsigned char divider)
+{
+ struct mxs_clkctrl_regs *clkctrl_regs =
+ (struct mxs_clkctrl_regs *)IMX_CCM_BASE;
+
+ /* Gate EMI clock */
+ writeb(CLKCTRL_FRAC_CLKGATE,
+ &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_EMI]);
+
+ /* Set fractional divider for ref_emi */
+ writeb(CLKCTRL_FRAC_CLKGATE | (divider & CLKCTRL_FRAC_FRAC_MASK),
+ &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
+
+ /* Ungate EMI clock */
+ writeb(CLKCTRL_FRAC_CLKGATE,
+ &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_EMI]);
+
+ mxs_early_delay(11000);
+
+ /* Set EMI clock divider for EMI clock to 411 / 2 = 205MHz */
+ writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) |
+ (1 << CLKCTRL_EMI_DIV_XTAL_OFFSET),
+ &clkctrl_regs->hw_clkctrl_emi);
+
+ /* Unbypass EMI */
+ writel(CLKCTRL_CLKSEQ_BYPASS_EMI,
+ &clkctrl_regs->hw_clkctrl_clkseq_clr);
+
+ mxs_early_delay(10000);
+}
+
+void mxs_mem_setup_cpu_and_hbus(void)
+{
+ struct mxs_clkctrl_regs *clkctrl_regs =
+ (struct mxs_clkctrl_regs *)IMX_CCM_BASE;
+
+ /* Set fractional divider for ref_cpu to 480 * 18 / 19 = 454MHz
+ * and ungate CPU clock */
+ writeb(19 & CLKCTRL_FRAC_FRAC_MASK,
+ (uint8_t *)&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
+
+ /* Set CPU bypass */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_set);
+
+ /* HBUS = 151MHz */
+ writel(CLKCTRL_HBUS_DIV_MASK, &clkctrl_regs->hw_clkctrl_hbus_set);
+ writel(((~3) << CLKCTRL_HBUS_DIV_OFFSET) & CLKCTRL_HBUS_DIV_MASK,
+ &clkctrl_regs->hw_clkctrl_hbus_clr);
+
+ mxs_early_delay(10000);
+
+ /* CPU clock divider = 1 */
+ clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu,
+ CLKCTRL_CPU_DIV_CPU_MASK, 1);
+
+ /* Disable CPU bypass */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_clr);
+
+ mxs_early_delay(15000);
+}
+
+void mxs_mem_setup_vdda(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ writel((0xc << POWER_VDDACTRL_TRG_OFFSET) |
+ (0x7 << POWER_VDDACTRL_BO_OFFSET_OFFSET) |
+ POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW,
+ &power_regs->hw_power_vddactrl);
+}
+
+static void mx23_mem_setup_vddmem(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /* We must wait before and after disabling the current limiter! */
+ mxs_early_delay(10000);
+
+ clrbits_le32(&power_regs->hw_power_vddmemctrl,
+ POWER_VDDMEMCTRL_ENABLE_ILIMIT);
+
+ mxs_early_delay(10000);
+}
+
+void mx23_mem_init(void)
+{
+ mxs_early_delay(11000);
+
+ /* Fractional divider for ref_emi is 33 ; 480 * 18 / 33 = 266MHz */
+ mxs_mem_init_clock(33);
+
+ mxs_mem_setup_vdda();
+
+ /*
+ * Reset/ungate the EMI block. This is essential, otherwise the system
+ * suffers from memory instability. This thing is mx23 specific and is
+ * no longer present on mx28.
+ */
+ mxs_early_reset_block((struct mxs_register_32 *)IMX_EMI_BASE);
+
+ mx23_mem_setup_vddmem();
+
+ /*
+ * Configure the DRAM registers
+ */
+
+ /* Clear START and SREFRESH bit from DRAM_CTL8 */
+ clrbits_le32(IMX_SDRAMC_BASE + 0x20, (1 << 16) | (1 << 8));
+
+ mx23_initialize_dram_values();
+
+ /* Set START bit in DRAM_CTL8 */
+ setbits_le32(IMX_SDRAMC_BASE + 0x20, 1 << 16);
+
+ clrbits_le32(IMX_SDRAMC_BASE + 0x40, 1 << 17);
+
+ /* Wait for EMI_STAT bit DRAM_HALTED */
+ for (;;) {
+ if (!(readl(IMX_EMI_BASE + 0x10) & (1 << 1)))
+ break;
+ mxs_early_delay(1000);
+ }
+
+ /* Adjust EMI port priority. */
+ clrsetbits_le32(0x80020000, 0x1f << 16, 0x2);
+ mxs_early_delay(20000);
+
+ setbits_le32(IMX_SDRAMC_BASE + 0x40, 1 << 19);
+ setbits_le32(IMX_SDRAMC_BASE + 0x40, 1 << 11);
+
+ mxs_early_delay(10000);
+
+ mxs_mem_setup_cpu_and_hbus();
+}
+
+#define PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2 (0x3 << 16)
+
+void mx28_mem_init(void)
+{
+ mxs_early_delay(11000);
+
+ /* Fractional divider for ref_emi is 21 ; 480 * 18 / 21 = 411MHz */
+ mxs_mem_init_clock(21);
+
+ mxs_mem_setup_vdda();
+
+ /* Set DDR2 mode */
+ writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2,
+ IMX_IOMUXC_BASE + 0x1b80);
+
+ /*
+ * Configure the DRAM registers
+ */
+
+ /* Clear START bit from DRAM_CTL16 */
+ clrbits_le32(IMX_SDRAMC_BASE + 0x40, 1);
+
+ mx28_initialize_dram_values();
+
+ /* Clear SREFRESH bit from DRAM_CTL17 */
+ clrbits_le32(IMX_SDRAMC_BASE + 0x44, 1);
+
+ /* Set START bit in DRAM_CTL16 */
+ setbits_le32(IMX_SDRAMC_BASE + 0x40, 1);
+
+ /* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */
+ while (!(readl(IMX_SDRAMC_BASE + 0xe8) & (1 << 20)))
+ ;
+
+ mxs_early_delay(10000);
+
+ mxs_mem_setup_cpu_and_hbus();
+}
diff --git a/arch/arm/mach-mxs/mxs23img.cfg b/arch/arm/mach-mxs/mxs23img.cfg
new file mode 100644
index 0000000000..34e88483f0
--- /dev/null
+++ b/arch/arm/mach-mxs/mxs23img.cfg
@@ -0,0 +1,6 @@
+SECTION 0x0 BOOTABLE
+ TAG LAST
+ LOAD 0x1000 @PREP@
+ CALL 0x1000 0x0
+ LOAD 0x40002000 @BOOTLOADER@
+ CALL 0x40002000 0x0
diff --git a/arch/arm/mach-mxs/mxs28img.cfg b/arch/arm/mach-mxs/mxs28img.cfg
new file mode 100644
index 0000000000..0ff2c35dd5
--- /dev/null
+++ b/arch/arm/mach-mxs/mxs28img.cfg
@@ -0,0 +1,8 @@
+SECTION 0x0 BOOTABLE
+ TAG LAST
+ LOAD 0x1000 @PREP@
+ LOAD IVT 0x8000 0x1000
+ CALL HAB 0x8000 0x0
+ LOAD 0x40002000 @BOOTLOADER@
+ LOAD IVT 0x8000 0x40002000
+ CALL HAB 0x8000 0x0
diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c
index c7c24e0980..abdd445b5d 100644
--- a/arch/arm/mach-mxs/ocotp.c
+++ b/arch/arm/mach-mxs/ocotp.c
@@ -27,7 +27,6 @@
#include <mach/generic.h>
#include <mach/ocotp.h>
-#include <mach/imx-regs.h>
#include <mach/power.h>
#define DRIVERNAME "ocotp"
diff --git a/arch/arm/mach-mxs/power-init.c b/arch/arm/mach-mxs/power-init.c
new file mode 100644
index 0000000000..977c6e4e27
--- /dev/null
+++ b/arch/arm/mach-mxs/power-init.c
@@ -0,0 +1,1272 @@
+/*
+ * Freescale i.MX28 Boot PMIC init
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <config.h>
+#include <io.h>
+#include <mach/imx-regs.h>
+
+#include <mach/generic.h>
+#include <mach/init.h>
+#ifdef CONFIG_ARCH_IMX23
+#include <mach/regs-clkctrl-mx23.h>
+#endif
+#ifdef CONFIG_ARCH_IMX28
+#include <mach/regs-clkctrl-mx28.h>
+#endif
+#include <mach/regs-power-mx28.h>
+#include <mach/regs-rtc.h>
+#include <mach/regs-lradc.h>
+
+/*
+ * This delay function is intended to be used only in early stage of boot, where
+ * clock are not set up yet. The timer used here is reset on every boot and
+ * takes a few seconds to roll. The boot doesn't take that long, so to keep the
+ * code simple, it doesn't take rolling into consideration.
+ */
+void mxs_early_delay(int delay)
+{
+ void __iomem *digctl_regs = IOMEM(IMX_DIGCTL_BASE);
+ uint32_t st = readl(digctl_regs + 0xc0);
+
+ st += delay;
+
+ while (st > readl(digctl_regs + 0xc0));
+}
+
+static inline void charger_4p2_disable(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ if (cpu_is_mx28())
+ writel(MX28_POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+ &power_regs->hw_power_5vctrl_set);
+ else
+ writel(MX23_POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+ &power_regs->hw_power_5vctrl_set);
+}
+
+static inline void charger_4p2_enable(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ if (cpu_is_mx28())
+ writel(MX28_POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+ &power_regs->hw_power_5vctrl_clr);
+ else
+ writel(MX23_POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+ &power_regs->hw_power_5vctrl_clr);
+}
+
+/**
+ * mxs_power_clock2xtal() - Switch CPU core clock source to 24MHz XTAL
+ *
+ * This function switches the CPU core clock from PLL to 24MHz XTAL
+ * oscilator. This is necessary if the PLL is being reconfigured to
+ * prevent crash of the CPU core.
+ */
+static void mxs_power_clock2xtal(void)
+{
+ struct mxs_clkctrl_regs *clkctrl_regs =
+ (struct mxs_clkctrl_regs *)IMX_CCM_BASE;
+
+ /* Set XTAL as CPU reference clock */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_set);
+}
+
+/**
+ * mxs_power_clock2pll() - Switch CPU core clock source to PLL
+ *
+ * This function switches the CPU core clock from 24MHz XTAL oscilator
+ * to PLL. This can only be called once the PLL has re-locked and once
+ * the PLL is stable after reconfiguration.
+ */
+static void mxs_power_clock2pll(void)
+{
+ struct mxs_clkctrl_regs *clkctrl_regs =
+ (struct mxs_clkctrl_regs *)IMX_CCM_BASE;
+
+ setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
+ CLKCTRL_PLL0CTRL0_POWER);
+ mxs_early_delay(100);
+ setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
+ CLKCTRL_CLKSEQ_BYPASS_CPU);
+}
+
+/**
+ * mxs_power_set_auto_restart() - Set the auto-restart bit
+ *
+ * This function ungates the RTC block and sets the AUTO_RESTART
+ * bit to work around a design bug on MX28EVK Rev. A .
+ */
+
+static void mxs_power_set_auto_restart(void)
+{
+ struct mxs_rtc_regs *rtc_regs =
+ (struct mxs_rtc_regs *)IMX_WDT_BASE;
+
+ writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr);
+ while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST)
+ ;
+
+ writel(RTC_CTRL_CLKGATE, &rtc_regs->hw_rtc_ctrl_clr);
+ while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE)
+ ;
+
+ /* Do nothing if flag already set */
+ if (readl(&rtc_regs->hw_rtc_persistent0) & RTC_PERSISTENT0_AUTO_RESTART)
+ return;
+
+ while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK)
+ ;
+
+ setbits_le32(&rtc_regs->hw_rtc_persistent0,
+ RTC_PERSISTENT0_AUTO_RESTART);
+ writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_set);
+ writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_clr);
+ while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK)
+ ;
+ while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK)
+ ;
+}
+
+/**
+ * mxs_power_set_linreg() - Set linear regulators 25mV below DC-DC converter
+ *
+ * This function configures the VDDIO, VDDA and VDDD linear regulators output
+ * to be 25mV below the VDDIO, VDDA and VDDD output from the DC-DC switching
+ * converter. This is the recommended setting for the case where we use both
+ * linear regulators and DC-DC converter to power the VDDIO rail.
+ */
+static void mxs_power_set_linreg(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /* Set linear regulator 25mV below switching converter */
+ clrsetbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_LINREG_OFFSET_MASK,
+ POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
+
+ clrsetbits_le32(&power_regs->hw_power_vddactrl,
+ POWER_VDDACTRL_LINREG_OFFSET_MASK,
+ POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW);
+
+ clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
+ POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
+}
+
+/**
+ * mxs_get_batt_volt() - Measure battery input voltage
+ *
+ * This function retrieves the battery input voltage and returns it.
+ */
+static int mxs_get_batt_volt(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t volt = readl(&power_regs->hw_power_battmonitor);
+
+ volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
+ volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
+ volt *= 8;
+
+ return volt;
+}
+
+/**
+ * mxs_is_batt_ready() - Test if the battery provides enough voltage to boot
+ *
+ * This function checks if the battery input voltage is higher than 3.6V and
+ * therefore allows the system to successfully boot using this power source.
+ */
+static int mxs_is_batt_ready(void)
+{
+ return (mxs_get_batt_volt() >= 3600);
+}
+
+/**
+ * mxs_is_batt_good() - Test if battery is operational at all
+ *
+ * This function starts recharging the battery and tests if the input current
+ * provided by the 5V input recharging the battery is also sufficient to power
+ * the DC-DC converter.
+ */
+static int mxs_is_batt_good(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t volt = mxs_get_batt_volt();
+
+ if ((volt >= 2400) && (volt <= 4300))
+ return 1;
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+ 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+ charger_4p2_enable();
+
+ clrsetbits_le32(&power_regs->hw_power_charge,
+ POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
+ POWER_CHARGE_STOP_ILIMIT_10MA | 0x3);
+
+ writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr);
+ charger_4p2_enable();
+
+ mxs_early_delay(500000);
+
+ volt = mxs_get_batt_volt();
+
+ if (volt >= 3500)
+ return 0;
+
+ if (volt >= 2400)
+ return 1;
+
+ writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
+ &power_regs->hw_power_charge_clr);
+ writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
+
+ return 0;
+}
+
+/**
+ * mxs_power_setup_5v_detect() - Start the 5V input detection comparator
+ *
+ * This function enables the 5V detection comparator and sets the 5V valid
+ * threshold to 4.4V . We use 4.4V threshold here to make sure that even
+ * under high load, the voltage drop on the 5V input won't be so critical
+ * to cause undervolt on the 4P2 linear regulator supplying the DC-DC
+ * converter and thus making the system crash.
+ */
+static void mxs_power_setup_5v_detect(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /* Start 5V detection */
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_VBUSVALID_TRSH_MASK,
+ POWER_5VCTRL_VBUSVALID_TRSH_4V4 |
+ POWER_5VCTRL_PWRUP_VBUS_CMPS);
+}
+
+/**
+ * mxs_src_power_init() - Preconfigure the power block
+ *
+ * This function configures reasonable values for the DC-DC control loop
+ * and battery monitor.
+ */
+static void mxs_src_power_init(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /* Improve efficieny and reduce transient ripple */
+ writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST |
+ POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set);
+
+ clrsetbits_le32(&power_regs->hw_power_dclimits,
+ POWER_DCLIMITS_POSLIMIT_BUCK_MASK,
+ 0x30 << POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET);
+
+ setbits_le32(&power_regs->hw_power_battmonitor,
+ POWER_BATTMONITOR_EN_BATADJ);
+
+ /* Increase the RCSCALE level for quick DCDC response to dynamic load */
+ clrsetbits_le32(&power_regs->hw_power_loopctrl,
+ POWER_LOOPCTRL_EN_RCSCALE_MASK,
+ POWER_LOOPCTRL_RCSCALE_THRESH |
+ POWER_LOOPCTRL_EN_RCSCALE_8X);
+
+ clrsetbits_le32(&power_regs->hw_power_minpwr,
+ POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
+
+ /* 5V to battery handoff ... FIXME */
+ setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+ mxs_early_delay(30);
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+}
+
+/**
+ * mxs_power_init_4p2_params() - Configure the parameters of the 4P2 regulator
+ *
+ * This function configures the necessary parameters for the 4P2 linear
+ * regulator to supply the DC-DC converter from 5V input.
+ */
+static void mxs_power_init_4p2_params(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /* Setup 4P2 parameters */
+ clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK,
+ POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET));
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_HEADROOM_ADJ_MASK,
+ 0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET);
+
+ clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_DROPOUT_CTRL_MASK,
+ POWER_DCDC4P2_DROPOUT_CTRL_100MV |
+ POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL);
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+ 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+}
+
+/**
+ * mxs_enable_4p2_dcdc_input() - Enable or disable the DCDC input from 4P2
+ * @xfer: Select if the input shall be enabled or disabled
+ *
+ * This function enables or disables the 4P2 input into the DC-DC converter.
+ */
+static void mxs_enable_4p2_dcdc_input(int xfer)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo;
+ uint32_t prev_5v_brnout, prev_5v_droop;
+
+ prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) &
+ POWER_5VCTRL_PWDN_5VBRNOUT;
+ prev_5v_droop = readl(&power_regs->hw_power_ctrl) &
+ POWER_CTRL_ENIRQ_VDD5V_DROOP;
+
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
+ writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
+ &power_regs->hw_power_reset);
+
+ clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP);
+
+ if (xfer && (readl(&power_regs->hw_power_5vctrl) &
+ POWER_5VCTRL_ENABLE_DCDC)) {
+ return;
+ }
+
+ /*
+ * Recording orignal values that will be modified temporarlily
+ * to handle a chip bug. See chip errata for CQ ENGR00115837
+ */
+ tmp = readl(&power_regs->hw_power_5vctrl);
+ vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK;
+ vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT;
+
+ pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO;
+
+ /*
+ * Disable mechanisms that get erroneously tripped by when setting
+ * the DCDC4P2 EN_DCDC
+ */
+ clrbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_VBUSVALID_5VDETECT |
+ POWER_5VCTRL_VBUSVALID_TRSH_MASK);
+
+ writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set);
+
+ if (xfer) {
+ setbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_DCDC_XFER);
+ mxs_early_delay(20);
+ clrbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_DCDC_XFER);
+
+ setbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_ENABLE_DCDC);
+ } else {
+ setbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_ENABLE_DCDC);
+ }
+
+ mxs_early_delay(25);
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh);
+
+ if (vbus_5vdetect)
+ writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set);
+
+ if (!pwd_bo)
+ clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO);
+
+ while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ)
+ writel(POWER_CTRL_VBUS_VALID_IRQ,
+ &power_regs->hw_power_ctrl_clr);
+
+ if (prev_5v_brnout) {
+ writel(POWER_5VCTRL_PWDN_5VBRNOUT,
+ &power_regs->hw_power_5vctrl_set);
+ writel(POWER_RESET_UNLOCK_KEY,
+ &power_regs->hw_power_reset);
+ } else {
+ writel(POWER_5VCTRL_PWDN_5VBRNOUT,
+ &power_regs->hw_power_5vctrl_clr);
+ writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
+ &power_regs->hw_power_reset);
+ }
+
+ while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ)
+ writel(POWER_CTRL_VDD5V_DROOP_IRQ,
+ &power_regs->hw_power_ctrl_clr);
+
+ if (prev_5v_droop)
+ clrbits_le32(&power_regs->hw_power_ctrl,
+ POWER_CTRL_ENIRQ_VDD5V_DROOP);
+ else
+ setbits_le32(&power_regs->hw_power_ctrl,
+ POWER_CTRL_ENIRQ_VDD5V_DROOP);
+}
+
+/**
+ * mxs_power_init_4p2_regulator() - Start the 4P2 regulator
+ *
+ * This function enables the 4P2 regulator and switches the DC-DC converter
+ * to use the 4P2 input.
+ */
+static void mxs_power_init_4p2_regulator(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t tmp, tmp2;
+
+ setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2);
+
+ writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set);
+
+ writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+ &power_regs->hw_power_5vctrl_clr);
+ clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK);
+
+ /* Power up the 4p2 rail and logic/control */
+ charger_4p2_enable();
+
+ /*
+ * Start charging up the 4p2 capacitor. We ramp of this charge
+ * gradually to avoid large inrush current from the 5V cable which can
+ * cause transients/problems
+ */
+ mxs_enable_4p2_dcdc_input(0);
+
+ if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
+ /*
+ * If we arrived here, we were unable to recover from mx23 chip
+ * errata 5837. 4P2 is disabled and sufficient battery power is
+ * not present. Exiting to not enable DCDC power during 5V
+ * connected state.
+ */
+ clrbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_ENABLE_DCDC);
+ charger_4p2_disable();
+ hang();
+ }
+
+ /*
+ * Here we set the 4p2 brownout level to something very close to 4.2V.
+ * We then check the brownout status. If the brownout status is false,
+ * the voltage is already close to the target voltage of 4.2V so we
+ * can go ahead and set the 4P2 current limit to our max target limit.
+ * If the brownout status is true, we need to ramp us the current limit
+ * so that we don't cause large inrush current issues. We step up the
+ * current limit until the brownout status is false or until we've
+ * reached our maximum defined 4p2 current limit.
+ */
+ clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_BO_MASK,
+ 22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
+
+ if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) {
+ setbits_le32(&power_regs->hw_power_5vctrl,
+ 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+ } else {
+ tmp = (readl(&power_regs->hw_power_5vctrl) &
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >>
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
+ while (tmp < 0x3f) {
+ if (!(readl(&power_regs->hw_power_sts) &
+ POWER_STS_DCDC_4P2_BO)) {
+ tmp = readl(&power_regs->hw_power_5vctrl);
+ tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
+ mxs_early_delay(100);
+ writel(tmp, &power_regs->hw_power_5vctrl);
+ break;
+ } else {
+ tmp++;
+ tmp2 = readl(&power_regs->hw_power_5vctrl);
+ tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK;
+ tmp2 |= tmp <<
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET;
+ writel(tmp2, &power_regs->hw_power_5vctrl);
+ mxs_early_delay(100);
+ }
+ }
+ }
+
+ clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK);
+ writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+}
+
+/**
+ * mxs_power_init_dcdc_4p2_source() - Switch DC-DC converter to 4P2 source
+ *
+ * This function configures the DC-DC converter to be supplied from the 4P2
+ * linear regulator.
+ */
+static void mxs_power_init_dcdc_4p2_source(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ if (!(readl(&power_regs->hw_power_dcdc4p2) &
+ POWER_DCDC4P2_ENABLE_DCDC)) {
+ hang();
+ }
+
+ mxs_enable_4p2_dcdc_input(1);
+
+ if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
+ clrbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_ENABLE_DCDC);
+ writel(POWER_5VCTRL_ENABLE_DCDC,
+ &power_regs->hw_power_5vctrl_clr);
+ charger_4p2_disable();
+ }
+}
+
+/**
+ * mxs_power_enable_4p2() - Power up the 4P2 regulator
+ *
+ * This function drives the process of powering up the 4P2 linear regulator
+ * and switching the DC-DC converter input over to the 4P2 linear regulator.
+ */
+static void mxs_power_enable_4p2(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t vdddctrl, vddactrl, vddioctrl;
+ uint32_t tmp;
+
+ vdddctrl = readl(&power_regs->hw_power_vdddctrl);
+ vddactrl = readl(&power_regs->hw_power_vddactrl);
+ vddioctrl = readl(&power_regs->hw_power_vddioctrl);
+
+ setbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
+ POWER_VDDDCTRL_PWDN_BRNOUT);
+
+ setbits_le32(&power_regs->hw_power_vddactrl,
+ POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG |
+ POWER_VDDACTRL_PWDN_BRNOUT);
+
+ setbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT);
+
+ mxs_power_init_4p2_params();
+ mxs_power_init_4p2_regulator();
+
+ /* Shutdown battery (none present) */
+ if (!mxs_is_batt_ready()) {
+ clrbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_BO_MASK);
+ writel(POWER_CTRL_DCDC4P2_BO_IRQ,
+ &power_regs->hw_power_ctrl_clr);
+ writel(POWER_CTRL_ENIRQ_DCDC4P2_BO,
+ &power_regs->hw_power_ctrl_clr);
+ }
+
+ mxs_power_init_dcdc_4p2_source();
+
+ writel(vdddctrl, &power_regs->hw_power_vdddctrl);
+ mxs_early_delay(20);
+ writel(vddactrl, &power_regs->hw_power_vddactrl);
+ mxs_early_delay(20);
+ writel(vddioctrl, &power_regs->hw_power_vddioctrl);
+
+ /*
+ * Check if FET is enabled on either powerout and if so,
+ * disable load.
+ */
+ tmp = 0;
+ tmp |= !(readl(&power_regs->hw_power_vdddctrl) &
+ POWER_VDDDCTRL_DISABLE_FET);
+ tmp |= !(readl(&power_regs->hw_power_vddactrl) &
+ POWER_VDDACTRL_DISABLE_FET);
+ tmp |= !(readl(&power_regs->hw_power_vddioctrl) &
+ POWER_VDDIOCTRL_DISABLE_FET);
+ if (tmp)
+ writel(POWER_CHARGE_ENABLE_LOAD,
+ &power_regs->hw_power_charge_clr);
+}
+
+/**
+ * mxs_boot_valid_5v() - Boot from 5V supply
+ *
+ * This function configures the power block to boot from valid 5V input.
+ * This is called only if the 5V is reliable and can properly supply the
+ * CPU. This function proceeds to configure the 4P2 converter to be supplied
+ * from the 5V input.
+ */
+static void mxs_boot_valid_5v(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /*
+ * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V
+ * disconnect event. FIXME
+ */
+ writel(POWER_5VCTRL_VBUSVALID_5VDETECT,
+ &power_regs->hw_power_5vctrl_set);
+
+ /* Configure polarity to check for 5V disconnection. */
+ writel(POWER_CTRL_POLARITY_VBUSVALID |
+ POWER_CTRL_POLARITY_VDD5V_GT_VDDIO,
+ &power_regs->hw_power_ctrl_clr);
+
+ writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ,
+ &power_regs->hw_power_ctrl_clr);
+
+ mxs_power_enable_4p2();
+}
+
+/**
+ * mxs_powerdown() - Shut down the system
+ *
+ * This function powers down the CPU completely.
+ */
+static void mxs_powerdown(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset);
+ writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
+ &power_regs->hw_power_reset);
+}
+
+/**
+ * mxs_enable_battery_input() - Configure the power block to boot from battery input
+ *
+ * This function configures the power block to boot from the battery voltage
+ * supply.
+ */
+static void mxs_enable_battery_input(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
+
+ clrbits_le32(&power_regs->hw_power_dcdc4p2,
+ POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2);
+ writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr);
+
+ /* 5V to battery handoff. */
+ setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+ mxs_early_delay(30);
+ clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+
+ writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr);
+
+ clrsetbits_le32(&power_regs->hw_power_minpwr,
+ POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS);
+
+ mxs_power_set_linreg();
+
+ clrbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG);
+
+ clrbits_le32(&power_regs->hw_power_vddactrl,
+ POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG);
+
+ clrbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_DISABLE_FET);
+
+ charger_4p2_disable();
+
+ setbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_ENABLE_DCDC);
+
+ clrsetbits_le32(&power_regs->hw_power_5vctrl,
+ POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
+ 0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
+
+ mxs_power_enable_4p2();
+}
+
+/**
+ * mxs_handle_5v_conflict() - Test if the 5V input is reliable
+ *
+ * This function tests if the 5V input can reliably supply the system. If it
+ * can, then proceed to configuring the system to boot from 5V source, otherwise
+ * try booting from battery supply. If we can not boot from battery supply
+ * either, shut down the system.
+ */
+static void mxs_handle_5v_conflict(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t tmp;
+
+ setbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_BO_OFFSET_MASK);
+
+ for (;;) {
+ tmp = readl(&power_regs->hw_power_sts);
+
+ if (tmp & POWER_STS_VDDIO_BO) {
+ /*
+ * VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes
+ * unreliable
+ */
+ mxs_powerdown();
+ break;
+ }
+
+ if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
+ mxs_boot_valid_5v();
+ break;
+ } else {
+ mxs_powerdown();
+ break;
+ }
+
+ if (tmp & POWER_STS_PSWITCH_MASK) {
+ mxs_enable_battery_input();
+ break;
+ }
+ }
+}
+
+/**
+ * mxs_5v_boot() - Configure the power block to boot from 5V input
+ *
+ * This function handles configuration of the power block when supplied by
+ * a 5V input.
+ */
+static void mxs_5v_boot(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /*
+ * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID,
+ * but their implementation always returns 1 so we omit it here.
+ */
+ if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+ mxs_boot_valid_5v();
+ return;
+ }
+
+ mxs_early_delay(1000);
+ if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+ mxs_boot_valid_5v();
+ return;
+ }
+
+ mxs_handle_5v_conflict();
+}
+
+/**
+ * mxs_init_batt_bo() - Configure battery brownout threshold
+ *
+ * This function configures the battery input brownout threshold. The value
+ * at which the battery brownout happens is configured to 3.0V in the code.
+ */
+static void mxs_init_batt_bo(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ /* Brownout at 3V */
+ clrsetbits_le32(&power_regs->hw_power_battmonitor,
+ POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
+ 15 << POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET);
+
+ writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+ writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr);
+}
+
+/**
+ * mxs_switch_vddd_to_dcdc_source() - Switch VDDD rail to DC-DC converter
+ *
+ * This function turns off the VDDD linear regulator and therefore makes
+ * the VDDD rail be supplied only by the DC-DC converter.
+ */
+static void mxs_switch_vddd_to_dcdc_source(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ clrsetbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_LINREG_OFFSET_MASK,
+ POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
+
+ clrbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG |
+ POWER_VDDDCTRL_DISABLE_STEPPING);
+}
+
+/**
+ * mxs_power_configure_power_source() - Configure power block source
+ *
+ * This function is the core of the power configuration logic. The function
+ * selects the power block input source and configures the whole power block
+ * accordingly. After the configuration is complete and the system is stable
+ * again, the function switches the CPU clock source back to PLL. Finally,
+ * the function switches the voltage rails to DC-DC converter.
+ */
+static void mxs_power_configure_power_source(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ struct mxs_lradc_regs *lradc_regs =
+ (struct mxs_lradc_regs *)IMX_LRADC_BASE;
+
+ if (!(readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO)) {
+ /* 5V not detected, booting from battery. */
+ mxs_enable_battery_input();
+ return;
+ }
+
+ if (mxs_is_batt_ready()) {
+ /* 5V source detected, good battery detected. */
+ mxs_enable_battery_input();
+ return;
+ }
+
+ if (!mxs_is_batt_good()) {
+ /* 5V source detected, bad battery detected. */
+ writel(LRADC_CONVERSION_AUTOMATIC,
+ &lradc_regs->hw_lradc_conversion_clr);
+ clrbits_le32(&power_regs->hw_power_battmonitor,
+ POWER_BATTMONITOR_BATT_VAL_MASK);
+ }
+ mxs_5v_boot();
+}
+
+/**
+ * mxs_enable_output_rail_protection() - Enable power rail protection
+ *
+ * This function enables overload protection on the power rails. This is
+ * triggered if the power rails' voltage drops rapidly due to overload and
+ * in such case, the supply to the powerrail is cut-off, protecting the
+ * CPU from damage. Note that under such condition, the system will likely
+ * crash or misbehave.
+ */
+static void mxs_enable_output_rail_protection(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
+ POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+
+ setbits_le32(&power_regs->hw_power_vdddctrl,
+ POWER_VDDDCTRL_PWDN_BRNOUT);
+
+ setbits_le32(&power_regs->hw_power_vddactrl,
+ POWER_VDDACTRL_PWDN_BRNOUT);
+
+ setbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_PWDN_BRNOUT);
+}
+
+/**
+ * mxs_get_vddio_power_source_off() - Get VDDIO rail power source
+ *
+ * This function tests if the VDDIO rail is supplied by linear regulator
+ * or by the DC-DC converter. Returns 1 if powered by linear regulator,
+ * returns 0 if powered by the DC-DC converter.
+ */
+static int mxs_get_vddio_power_source_off(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t tmp;
+
+ if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+ tmp = readl(&power_regs->hw_power_vddioctrl);
+ if (tmp & POWER_VDDIOCTRL_DISABLE_FET) {
+ if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
+ POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) {
+ return 1;
+ }
+ }
+
+ if (!(readl(&power_regs->hw_power_5vctrl) &
+ POWER_5VCTRL_ENABLE_DCDC)) {
+ if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
+ POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+/**
+ * mxs_get_vddd_power_source_off() - Get VDDD rail power source
+ *
+ * This function tests if the VDDD rail is supplied by linear regulator
+ * or by the DC-DC converter. Returns 1 if powered by linear regulator,
+ * returns 0 if powered by the DC-DC converter.
+ */
+static int mxs_get_vddd_power_source_off(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t tmp;
+
+ tmp = readl(&power_regs->hw_power_vdddctrl);
+ if (tmp & POWER_VDDDCTRL_DISABLE_FET) {
+ if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
+ POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
+ return 1;
+ }
+ }
+
+ if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+ if (!(readl(&power_regs->hw_power_5vctrl) &
+ POWER_5VCTRL_ENABLE_DCDC)) {
+ return 1;
+ }
+ }
+
+ if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) {
+ if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) ==
+ POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+struct mxs_vddx_cfg {
+ uint32_t *reg;
+ uint8_t step_mV;
+ uint16_t lowest_mV;
+ int (*powered_by_linreg)(void);
+ uint32_t trg_mask;
+ uint32_t bo_irq;
+ uint32_t bo_enirq;
+ uint32_t bo_offset_mask;
+ uint32_t bo_offset_offset;
+};
+
+static const struct mxs_vddx_cfg mx23_vddio_cfg = {
+ .reg = &(((struct mxs_power_regs *)IMX_POWER_BASE)->
+ hw_power_vddioctrl),
+ .step_mV = 25,
+ .lowest_mV = 2800,
+ .powered_by_linreg = mxs_get_vddio_power_source_off,
+ .trg_mask = POWER_VDDIOCTRL_TRG_MASK,
+ .bo_irq = POWER_CTRL_VDDIO_BO_IRQ,
+ .bo_enirq = POWER_CTRL_ENIRQ_VDDIO_BO,
+ .bo_offset_mask = POWER_VDDIOCTRL_BO_OFFSET_MASK,
+ .bo_offset_offset = POWER_VDDIOCTRL_BO_OFFSET_OFFSET,
+};
+
+static const struct mxs_vddx_cfg mx28_vddio_cfg = {
+ .reg = &(((struct mxs_power_regs *)IMX_POWER_BASE)->
+ hw_power_vddioctrl),
+ .step_mV = 50,
+ .lowest_mV = 2800,
+ .powered_by_linreg = mxs_get_vddio_power_source_off,
+ .trg_mask = POWER_VDDIOCTRL_TRG_MASK,
+ .bo_irq = POWER_CTRL_VDDIO_BO_IRQ,
+ .bo_enirq = POWER_CTRL_ENIRQ_VDDIO_BO,
+ .bo_offset_mask = POWER_VDDIOCTRL_BO_OFFSET_MASK,
+ .bo_offset_offset = POWER_VDDIOCTRL_BO_OFFSET_OFFSET,
+};
+
+static const struct mxs_vddx_cfg mxs_vddd_cfg = {
+ .reg = &(((struct mxs_power_regs *)IMX_POWER_BASE)->
+ hw_power_vdddctrl),
+ .step_mV = 25,
+ .lowest_mV = 800,
+ .powered_by_linreg = mxs_get_vddd_power_source_off,
+ .trg_mask = POWER_VDDDCTRL_TRG_MASK,
+ .bo_irq = POWER_CTRL_VDDD_BO_IRQ,
+ .bo_enirq = POWER_CTRL_ENIRQ_VDDD_BO,
+ .bo_offset_mask = POWER_VDDDCTRL_BO_OFFSET_MASK,
+ .bo_offset_offset = POWER_VDDDCTRL_BO_OFFSET_OFFSET,
+};
+
+static const struct mxs_vddx_cfg mxs_vddmem_cfg = {
+ .reg = &(((struct mxs_power_regs *)IMX_POWER_BASE)->
+ hw_power_vddmemctrl),
+ .step_mV = 50,
+ .lowest_mV = 1700,
+ .powered_by_linreg = NULL,
+ .trg_mask = POWER_VDDMEMCTRL_TRG_MASK,
+ .bo_irq = 0,
+ .bo_enirq = 0,
+ .bo_offset_mask = 0,
+ .bo_offset_offset = 0,
+};
+
+/**
+ * mxs_power_set_vddx() - Configure voltage on DC-DC converter rail
+ * @cfg: Configuration data of the DC-DC converter rail
+ * @new_target: New target voltage of the DC-DC converter rail
+ * @new_brownout: New brownout trigger voltage
+ *
+ * This function configures the output voltage on the DC-DC converter rail.
+ * The rail is selected by the @cfg argument. The new voltage target is
+ * selected by the @new_target and the voltage is specified in mV. The
+ * new brownout value is selected by the @new_brownout argument and the
+ * value is also in mV.
+ */
+static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg,
+ uint32_t new_target, uint32_t new_brownout)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+ uint32_t cur_target, diff, bo_int = 0;
+ uint32_t powered_by_linreg = 0;
+ int adjust_up, tmp;
+
+ new_brownout = DIV_ROUND_CLOSEST(new_target - new_brownout, cfg->step_mV);
+
+ cur_target = readl(cfg->reg);
+ cur_target &= cfg->trg_mask;
+ cur_target *= cfg->step_mV;
+ cur_target += cfg->lowest_mV;
+
+ adjust_up = new_target > cur_target;
+ if (cfg->powered_by_linreg)
+ powered_by_linreg = cfg->powered_by_linreg();
+
+ if (adjust_up && cfg->bo_irq) {
+ if (powered_by_linreg) {
+ bo_int = readl(cfg->reg);
+ clrbits_le32(cfg->reg, cfg->bo_enirq);
+ }
+ setbits_le32(cfg->reg, cfg->bo_offset_mask);
+ }
+
+ do {
+ if (abs(new_target - cur_target) > 100) {
+ if (adjust_up)
+ diff = cur_target + 100;
+ else
+ diff = cur_target - 100;
+ } else {
+ diff = new_target;
+ }
+
+ diff -= cfg->lowest_mV;
+ diff /= cfg->step_mV;
+
+ clrsetbits_le32(cfg->reg, cfg->trg_mask, diff);
+
+ if (powered_by_linreg ||
+ (readl(&power_regs->hw_power_sts) &
+ POWER_STS_VDD5V_GT_VDDIO))
+ mxs_early_delay(500);
+ else {
+ for (;;) {
+ tmp = readl(&power_regs->hw_power_sts);
+ if (tmp & POWER_STS_DC_OK)
+ break;
+ }
+ }
+
+ cur_target = readl(cfg->reg);
+ cur_target &= cfg->trg_mask;
+ cur_target *= cfg->step_mV;
+ cur_target += cfg->lowest_mV;
+ } while (new_target > cur_target);
+
+ if (cfg->bo_irq) {
+ if (adjust_up && powered_by_linreg) {
+ writel(cfg->bo_irq, &power_regs->hw_power_ctrl_clr);
+ if (bo_int & cfg->bo_enirq)
+ setbits_le32(cfg->reg, cfg->bo_enirq);
+ }
+
+ clrsetbits_le32(cfg->reg, cfg->bo_offset_mask,
+ new_brownout << cfg->bo_offset_offset);
+ }
+}
+
+/**
+ * mxs_setup_batt_detect() - Start the battery voltage measurement logic
+ *
+ * This function starts and configures the LRADC block. This allows the
+ * power initialization code to measure battery voltage and based on this
+ * knowledge, decide whether to boot at all, boot from battery or boot
+ * from 5V input.
+ */
+static void mxs_setup_batt_detect(void)
+{
+ mxs_lradc_init();
+ mxs_lradc_enable_batt_measurement();
+ mxs_early_delay(10);
+}
+
+/**
+ * mx23_ungate_power() - Ungate the POWER block
+ *
+ * This function ungates clock to the power block. In case the power block
+ * was still gated at this point, it will not be possible to configure the
+ * block and therefore the power initialization would fail. This function
+ * is only needed on i.MX233, on i.MX28 the power block is always ungated.
+ */
+static void mx23_ungate_power(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ writel(MX23_POWER_CTRL_CLKGATE, &power_regs->hw_power_ctrl_clr);
+}
+
+/**
+ * mx23_power_init() - The power block init main function
+ *
+ * This function calls all the power block initialization functions in
+ * proper sequence to start the power block.
+ */
+static void __mx23_power_init(int has_battery)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ mx23_ungate_power();
+
+ mxs_power_clock2xtal();
+ mxs_power_set_auto_restart();
+ mxs_power_set_linreg();
+ mxs_power_setup_5v_detect();
+
+ mxs_setup_batt_detect();
+
+ mxs_src_power_init();
+
+ if (has_battery)
+ mxs_power_configure_power_source();
+ else
+ mxs_enable_battery_input();
+
+ mxs_power_clock2pll();
+
+ mxs_init_batt_bo();
+
+ mxs_switch_vddd_to_dcdc_source();
+
+ /* Fire up the VDDMEM LinReg now that we're all set. */
+ writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT,
+ &power_regs->hw_power_vddmemctrl);
+
+ mxs_enable_output_rail_protection();
+
+ mxs_power_set_vddx(&mx23_vddio_cfg, 3300, 3150);
+ mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000);
+ mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700);
+
+ writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
+ POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ |
+ POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ |
+ POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+
+ writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set);
+
+ mxs_early_delay(1000);
+}
+
+void mx23_power_init(void)
+{
+ __mx23_power_init(1);
+}
+
+void mx23_power_init_battery_input(void)
+{
+ __mx23_power_init(0);
+}
+
+/**
+ * mx28_power_init() - The power block init main function
+ *
+ * This function calls all the power block initialization functions in
+ * proper sequence to start the power block.
+ */
+static void __mx28_power_init(int has_battery)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ mxs_power_clock2xtal();
+ mxs_power_set_auto_restart();
+ mxs_power_set_linreg();
+ mxs_power_setup_5v_detect();
+
+ mxs_setup_batt_detect();
+
+ mxs_src_power_init();
+
+ if (has_battery)
+ mxs_power_configure_power_source();
+ else
+ mxs_enable_battery_input();
+
+ mxs_power_clock2pll();
+
+ mxs_init_batt_bo();
+
+ mxs_switch_vddd_to_dcdc_source();
+
+ mxs_enable_output_rail_protection();
+
+ mxs_power_set_vddx(&mx28_vddio_cfg, 3300, 3150);
+ mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000);
+
+ writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
+ POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ |
+ POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ |
+ POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
+
+ writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set);
+
+ mxs_early_delay(1000);
+}
+
+void mx28_power_init(void)
+{
+ __mx28_power_init(1);
+}
+
+void mx28_power_init_battery_input(void)
+{
+ __mx28_power_init(0);
+}
+
+/**
+ * mxs_power_wait_pswitch() - Wait for power switch to be pressed
+ *
+ * This function waits until the power-switch was pressed to start booting
+ * the board.
+ */
+void mxs_power_wait_pswitch(void)
+{
+ struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)IMX_POWER_BASE;
+
+ while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
+ ;
+}
diff --git a/arch/arm/mach-mxs/soc-imx23.c b/arch/arm/mach-mxs/soc-imx23.c
index 825ea20a55..b21986536f 100644
--- a/arch/arm/mach-mxs/soc-imx23.c
+++ b/arch/arm/mach-mxs/soc-imx23.c
@@ -16,7 +16,7 @@
#include <common.h>
#include <init.h>
-#include <mach/imx-regs.h>
+#include <mach/imx23-regs.h>
#include <io.h>
#define HW_CLKCTRL_RESET 0x120
diff --git a/arch/arm/mach-mxs/soc-imx28.c b/arch/arm/mach-mxs/soc-imx28.c
index 01bc20a6f0..c7252f537e 100644
--- a/arch/arm/mach-mxs/soc-imx28.c
+++ b/arch/arm/mach-mxs/soc-imx28.c
@@ -16,7 +16,7 @@
#include <common.h>
#include <init.h>
-#include <mach/imx-regs.h>
+#include <mach/imx28-regs.h>
#include <io.h>
#define HW_CLKCTRL_RESET 0x1e0
diff --git a/arch/arm/mach-mxs/usb-imx23.c b/arch/arm/mach-mxs/usb-imx23.c
index 8bed11deb8..e626396f9d 100644
--- a/arch/arm/mach-mxs/usb-imx23.c
+++ b/arch/arm/mach-mxs/usb-imx23.c
@@ -15,7 +15,7 @@
*/
#include <common.h>
#include <io.h>
-#include <mach/imx-regs.h>
+#include <mach/imx23-regs.h>
#include <mach/power.h>
#define USBPHY_PWD (IMX_USBPHY_BASE + 0x0)
diff --git a/arch/arm/mach-mxs/usb-imx28.c b/arch/arm/mach-mxs/usb-imx28.c
index 1c982a0266..a87d4f6cbc 100644
--- a/arch/arm/mach-mxs/usb-imx28.c
+++ b/arch/arm/mach-mxs/usb-imx28.c
@@ -17,7 +17,7 @@
#include <common.h>
#include <io.h>
#include <errno.h>
-#include <mach/imx-regs.h>
+#include <mach/imx28-regs.h>
#define POWER_CTRL (IMX_POWER_BASE + 0x0)
#define POWER_CTRL_CLKGATE 0x40000000
diff --git a/common/Kconfig b/common/Kconfig
index 4614965899..00e4f36d62 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -882,6 +882,17 @@ config DEBUG_INITCALLS
bool "Trace initcalls"
help
If enabled this will print initcall traces.
+
+config PBL_CONSOLE
+ depends on DEBUG_LL
+ bool "Enable console support in PBL"
+ help
+ This enables printf/pr_* support in the PBL to get more
+ informational output earlier during startup. Note that
+ printf/pr_* need a valid C environment, so the binary
+ must be running at the address it's linked at and bss must
+ be cleared. On ARM that would be after setup_c().
+
endmenu
config HAS_DEBUG_LL
diff --git a/common/console_common.c b/common/console_common.c
index cc25f97d9d..df1b085982 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -101,7 +101,7 @@ void pr_puts(int level, const char *str)
{
struct log_entry *log;
- if (IS_ENABLED(CONFIG_LOGBUF)) {
+ if (IS_ENABLED(CONFIG_LOGBUF) && mem_malloc_is_initialized()) {
if (barebox_log_max_messages > 0)
log_clean(barebox_log_max_messages - 1);
diff --git a/common/memory.c b/common/memory.c
index 57c73abb22..4725f6e382 100644
--- a/common/memory.c
+++ b/common/memory.c
@@ -49,6 +49,13 @@ unsigned long mem_malloc_end(void)
tlsf_pool tlsf_mem_pool;
#endif
+int mem_malloc_initialized;
+
+int mem_malloc_is_initialized(void)
+{
+ return mem_malloc_initialized;
+}
+
void mem_malloc_init(void *start, void *end)
{
malloc_start = (unsigned long)start;
@@ -57,6 +64,7 @@ void mem_malloc_init(void *start, void *end)
#ifdef CONFIG_MALLOC_TLSF
tlsf_mem_pool = tlsf_create(start, end - start + 1);
#endif
+ mem_malloc_initialized = 1;
}
#if !defined __SANDBOX__ && !defined CONFIG_ARCH_EFI
diff --git a/common/misc.c b/common/misc.c
index 65f3306bee..6da71c7ab7 100644
--- a/common/misc.c
+++ b/common/misc.c
@@ -22,6 +22,7 @@
#include <magicvar.h>
#include <globalvar.h>
#include <environment.h>
+#include <led.h>
#include <of.h>
int errno;
@@ -188,3 +189,24 @@ EXPORT_SYMBOL(barebox_get_hostname);
BAREBOX_MAGICVAR_NAMED(global_hostname, global.hostname,
"shortname of the board. Also used as hostname for DHCP requests");
+
+void __noreturn panic(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ putchar('\n');
+ va_end(args);
+
+ dump_stack();
+
+ led_trigger(LED_TRIGGER_PANIC, TRIGGER_ENABLE);
+
+ if (IS_ENABLED(CONFIG_PANIC_HANG)) {
+ hang();
+ } else {
+ udelay(100000); /* allow messages to go out */
+ reset_cpu(0);
+ }
+}
+EXPORT_SYMBOL(panic);
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 1f84e9f6e9..8bf27c1c07 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -22,7 +22,7 @@
#include <io.h>
#include <linux/clkdev.h>
#include <linux/err.h>
-#include <mach/imx-regs.h>
+#include <mach/imx23-regs.h>
#include "clk.h"
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index aa2924c70e..77a13bc7ac 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -22,7 +22,7 @@
#include <io.h>
#include <linux/clkdev.h>
#include <linux/err.h>
-#include <mach/imx-regs.h>
+#include <mach/imx28-regs.h>
#include "clk.h"
diff --git a/drivers/mci/mxs.c b/drivers/mci/mxs.c
index d6565ca2f8..367964c1d0 100644
--- a/drivers/mci/mxs.c
+++ b/drivers/mci/mxs.c
@@ -40,7 +40,6 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/bitops.h>
-#include <mach/imx-regs.h>
#include <mach/mci.h>
#include <mach/clock.h>
#include <mach/ssp.h>
diff --git a/drivers/serial/serial_auart.c b/drivers/serial/serial_auart.c
index ae6c5b8219..87b2e33ca3 100644
--- a/drivers/serial/serial_auart.c
+++ b/drivers/serial/serial_auart.c
@@ -47,7 +47,6 @@
#include <linux/err.h>
#include <mach/clock.h>
-#include <mach/imx-regs.h>
#define HW_UARTAPP_CTRL0 (0x00000000)
diff --git a/drivers/serial/stm-serial.c b/drivers/serial/stm-serial.c
index 39ff7ae942..e5f57dc6e7 100644
--- a/drivers/serial/stm-serial.c
+++ b/drivers/serial/stm-serial.c
@@ -31,7 +31,6 @@
#include <malloc.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <mach/imx-regs.h>
#include <mach/clock.h>
#define UARTDBGDR 0x00
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 9a35e09b88..8932103475 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -25,7 +25,6 @@
#include <linux/err.h>
#include <asm/mmu.h>
#include <mach/generic.h>
-#include <mach/imx-regs.h>
#include <mach/clock.h>
#include <mach/ssp.h>
diff --git a/drivers/video/stm.c b/drivers/video/stm.c
index 175e4b611d..3c90c0dc3f 100644
--- a/drivers/video/stm.c
+++ b/drivers/video/stm.c
@@ -27,7 +27,6 @@
#include <stmp-device.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <mach/imx-regs.h>
#include <mach/fb.h>
#define HW_LCDIF_CTRL 0x00
diff --git a/images/.gitignore b/images/.gitignore
index d27e71a0c8..c5377d9f65 100644
--- a/images/.gitignore
+++ b/images/.gitignore
@@ -16,6 +16,8 @@
*.t124img.cfg
*.mlo
*.mlospi
+*.mxsbs
+*.mxssd
pbl.lds
barebox.x
barebox.z
diff --git a/images/Makefile b/images/Makefile
index c55cbdc1fb..7c3aaf7627 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -103,6 +103,7 @@ include $(srctree)/images/Makefile.mvebu
include $(srctree)/images/Makefile.rockchip
include $(srctree)/images/Makefile.socfpga
include $(srctree)/images/Makefile.tegra
+include $(srctree)/images/Makefile.mxs
targets += $(image-y) pbl.lds barebox.x barebox.z
targets += $(patsubst %,%.pblx,$(pblx-y))
@@ -119,5 +120,5 @@ images: $(addprefix $(obj)/, $(image-y)) FORCE
clean-files := *.pbl *.pblb *.pblx *.map start_*.imximg *.img barebox.z start_*.kwbimg \
start_*.kwbuartimg *.socfpgaimg *.mlo *.t20img *.t20img.cfg *.t30img \
- *.t30img.cfg *.t124img *.t124img.cfg *.mlospi *.mlo
+ *.t30img.cfg *.t124img *.t124img.cfg *.mlospi *.mlo *.mxsbs *.mxssd
clean-files += pbl.lds
diff --git a/images/Makefile.mxs b/images/Makefile.mxs
new file mode 100644
index 0000000000..abff255c3d
--- /dev/null
+++ b/images/Makefile.mxs
@@ -0,0 +1,43 @@
+#
+# barebox image generation Makefile for MXS images
+#
+
+# %.mxsbs - convert into MXS BootStream image
+# ----------------------------------------------------------------
+quiet_cmd_mxs_bootstream = MXS-BOOTSTREAM $@
+ cmd_mxs_bootstream = $(objtree)/scripts/mxsimage -c $(CFG_$(@F)) -b $< -o $@ -p $(word 2,$^)
+
+$(obj)/%.mxsbs: $(obj)/%.pblx $(obj)/prep_%.pblb FORCE
+ $(call if_changed,mxs_bootstream)
+
+# %.mxssd - convert into MXS SD card image
+# ----------------------------------------------------------------
+quiet_cmd_mxs_sd = MXS-SD $@
+ cmd_mxs_sd = $(objtree)/scripts/mxsboot sd $< $@
+
+$(obj)/%.mxssd: $(obj)/%
+ $(call if_changed,mxs_sd)
+
+board = $(srctree)/arch/$(ARCH)/boards
+mxs23cfg = $(srctree)/arch/arm/mach-mxs/mxs23img.cfg
+mxs28cfg = $(srctree)/arch/arm/mach-mxs/mxs28img.cfg
+
+pblx-$(CONFIG_MACH_TX28) += start_barebox_karo_tx28 prep_start_barebox_karo_tx28
+PREP_start_barebox_karo_tx28.pblx.mxsbs = start_barebox_karo_tx28_prep
+CFG_start_barebox_karo_tx28.mxsbs = $(mxs28cfg)
+FILE_barebox-karo-tx28-bootstream.img = start_barebox_karo_tx28.mxsbs
+image-$(CONFIG_MACH_TX28) += barebox-karo-tx28-bootstream.img
+FILE_barebox-karo-tx28-sd.img = start_barebox_karo_tx28.mxsbs.mxssd
+image-$(CONFIG_MACH_TX28) += barebox-karo-tx28-sd.img
+FILE_barebox-karo-tx28-2nd.img = start_barebox_karo_tx28.pblx
+image-$(CONFIG_MACH_TX28) += barebox-karo-tx28-2nd.img
+
+pblx-$(CONFIG_MACH_IMX233_OLINUXINO) += start_barebox_olinuxino_imx23 prep_start_barebox_olinuxino_imx23
+PREP_start_barebox_olinuxino_imx23.pblx.mxsbs = start_barebox_olinuxino_imx23_prep;
+CFG_start_barebox_olinuxino_imx23.mxsbs = $(mxs23cfg)
+FILE_barebox-olinuxino-imx23-bootstream.img = start_barebox_olinuxino_imx23.mxsbs
+image-$(CONFIG_MACH_IMX233_OLINUXINO) += barebox-olinuxino-imx23-bootstream.img
+FILE_barebox-olinuxino-imx23-sd.img = start_barebox_olinuxino_imx23.mxsbs.mxssd
+image-$(CONFIG_MACH_IMX233_OLINUXINO) += barebox-olinuxino-imx23-sd.img
+FILE_barebox-olinuxino-imx23-2nd.img = start_barebox_olinuxino_imx23.pblx
+image-$(CONFIG_MACH_IMX233_OLINUXINO) += barebox-olinuxino-imx23-2nd.img
diff --git a/include/malloc.h b/include/malloc.h
index a36f3c0de4..0d3c9e97a0 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -11,4 +11,6 @@ void *calloc(size_t, size_t);
void malloc_stats(void);
void *sbrk(ptrdiff_t increment);
+int mem_malloc_is_initialized(void);
+
#endif /* __MALLOC_H */
diff --git a/include/printk.h b/include/printk.h
index 22c6c732f7..a27ad514cf 100644
--- a/include/printk.h
+++ b/include/printk.h
@@ -22,18 +22,23 @@
/* debugging and troubleshooting/diagnostic helpers. */
#ifndef CONFIG_CONSOLE_NONE
-int pr_print(int level, const char *format, ...)
- __attribute__ ((format(__printf__, 2, 3)));
-
int dev_printf(int level, const struct device_d *dev, const char *format, ...)
__attribute__ ((format(__printf__, 3, 4)));
#else
-static inline int pr_print(int level, const char *format, ...)
+static inline int dev_printf(int level, const struct device_d *dev, const char *format, ...)
{
return 0;
}
+#endif
-static inline int dev_printf(int level, const struct device_d *dev, const char *format, ...)
+#if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \
+ (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE))
+int pr_print(int level, const char *format, ...)
+ __attribute__ ((format(__printf__, 2, 3)));
+#else
+static int pr_print(int level, const char *format, ...)
+ __attribute__ ((format(__printf__, 2, 3)));
+static inline int pr_print(int level, const char *format, ...)
{
return 0;
}
diff --git a/include/stdio.h b/include/stdio.h
index 71dbae35ca..f190911762 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -29,8 +29,6 @@ int getc(void);
int console_puts(unsigned int ch, const char *s);
void console_flush(void);
-
-int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
int vprintf(const char *fmt, va_list args);
#else
static inline int tstc(void)
@@ -52,13 +50,6 @@ static inline void console_putc(unsigned int ch, char c) {}
static inline void console_flush(void) {}
-static int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
-static inline int printf(const char *fmt, ...)
-{
- return 0;
-}
-
-
static inline int vprintf(const char *fmt, va_list args)
{
return 0;
@@ -74,6 +65,17 @@ static inline int ctrlc (void)
#endif
+#if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \
+ (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE))
+int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
+#else
+static int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2)));
+static inline int printf(const char *fmt, ...)
+{
+ return 0;
+}
+#endif
+
static inline int puts(const char *s)
{
return console_puts(CONSOLE_STDOUT, s);
diff --git a/lib/Makefile b/lib/Makefile
index a6c7dfbbbe..226570a7e6 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,8 +4,11 @@ obj-y += ctype.o
obj-y += rbtree.o
obj-y += display_options.o
obj-y += string.o
+obj-y += strtox.o
obj-y += vsprintf.o
+pbl-$(CONFIG_PBL_CONSOLE) += vsprintf.o
obj-y += div64.o
+pbl-y += div64.o
obj-y += misc.o
obj-$(CONFIG_PARAMETER) += parameter.o
obj-y += xfuncs.o
diff --git a/lib/strtox.c b/lib/strtox.c
new file mode 100644
index 0000000000..882865b45d
--- /dev/null
+++ b/lib/strtox.c
@@ -0,0 +1,68 @@
+#include <common.h>
+#include <linux/ctype.h>
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (*cp == '0') {
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1])) {
+ base = 16;
+ cp++;
+ }
+ if (!base) {
+ base = 8;
+ }
+ }
+ if (!base) {
+ base = 10;
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+EXPORT_SYMBOL(simple_strtoul);
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -simple_strtoul(cp+1,endp,base);
+ return simple_strtoul(cp,endp,base);
+}
+EXPORT_SYMBOL(simple_strtol);
+
+unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base)
+{
+ unsigned long long result = 0, value;
+
+ if (*cp == '0') {
+ cp++;
+ if ((*cp == 'x') && isxdigit (cp[1])) {
+ base = 16;
+ cp++;
+ }
+ if (!base) {
+ base = 8;
+ }
+ }
+ if (!base) {
+ base = 10;
+ }
+ while (isxdigit (*cp) && (value = isdigit (*cp)
+ ? *cp - '0'
+ : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) {
+ result = result * base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *) cp;
+ return result;
+}
+EXPORT_SYMBOL(simple_strtoull);
+
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 512c88247f..800ded7939 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -18,75 +18,11 @@
#include <kallsyms.h>
#include <common.h>
-#include <led.h>
-
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
- unsigned long result = 0,value;
-
- if (*cp == '0') {
- cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
- base = 16;
- cp++;
- }
- if (!base) {
- base = 8;
- }
- }
- if (!base) {
- base = 10;
- }
- while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
- ? toupper(*cp) : *cp)-'A'+10) < base) {
- result = result*base + value;
- cp++;
- }
- if (endp)
- *endp = (char *)cp;
- return result;
-}
-EXPORT_SYMBOL(simple_strtoul);
-
-long simple_strtol(const char *cp,char **endp,unsigned int base)
-{
- if(*cp=='-')
- return -simple_strtoul(cp+1,endp,base);
- return simple_strtoul(cp,endp,base);
-}
-EXPORT_SYMBOL(simple_strtol);
-
-unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base)
-{
- unsigned long long result = 0, value;
-
- if (*cp == '0') {
- cp++;
- if ((*cp == 'x') && isxdigit (cp[1])) {
- base = 16;
- cp++;
- }
- if (!base) {
- base = 8;
- }
- }
- if (!base) {
- base = 10;
- }
- while (isxdigit (*cp) && (value = isdigit (*cp)
- ? *cp - '0'
- : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) {
- result = result * base + value;
- cp++;
- }
- if (endp)
- *endp = (char *) cp;
- return result;
-}
-EXPORT_SYMBOL(simple_strtoull);
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
+#define is_alpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#define is_alnum(c) (is_digit(c) || is_alpha(c))
static int skip_atoi(const char **s)
{
@@ -239,6 +175,7 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
return buf;
}
+#ifndef __PBL__
static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
{
unsigned long value = (unsigned long) ptr;
@@ -341,6 +278,17 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
}
return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags);
}
+#else
+static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags)
+{
+ flags |= SMALL;
+ if (field_width == -1) {
+ field_width = 2*sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags);
+}
+#endif
/**
* vsnprintf - Format a string and place it in a buffer
@@ -417,7 +365,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
/* get field width */
field_width = -1;
- if (isdigit(*fmt))
+ if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
@@ -433,7 +381,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
precision = -1;
if (*fmt == '.') {
++fmt;
- if (isdigit(*fmt))
+ if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
@@ -488,7 +436,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
va_arg(args, void *),
field_width, precision, flags);
/* Skip all alphanumeric pointer suffixes */
- while (isalnum(fmt[1]))
+ while (is_alnum(fmt[1]))
fmt++;
continue;
@@ -680,24 +628,3 @@ char *asprintf(const char *fmt, ...)
return p;
}
EXPORT_SYMBOL(asprintf);
-
-void __noreturn panic(const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vprintf(fmt, args);
- putchar('\n');
- va_end(args);
-
- dump_stack();
-
- led_trigger(LED_TRIGGER_PANIC, TRIGGER_ENABLE);
-
- if (IS_ENABLED(CONFIG_PANIC_HANG)) {
- hang();
- } else {
- udelay(100000); /* allow messages to go out */
- reset_cpu(0);
- }
-}
-EXPORT_SYMBOL(panic);
diff --git a/pbl/Makefile b/pbl/Makefile
index a2d7468687..c5a08c1354 100644
--- a/pbl/Makefile
+++ b/pbl/Makefile
@@ -4,3 +4,4 @@
pbl-y += misc.o
pbl-y += string.o
pbl-y += decomp.o
+pbl-$(CONFIG_PBL_CONSOLE) += console.o
diff --git a/pbl/console.c b/pbl/console.c
new file mode 100644
index 0000000000..3875e2aafd
--- /dev/null
+++ b/pbl/console.c
@@ -0,0 +1,32 @@
+#include <common.h>
+#include <debug_ll.h>
+
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CFG_PBSIZE];
+
+ va_start(args, fmt);
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ puts_ll(printbuffer);
+
+ return i;
+}
+
+int pr_print(int level, const char *fmt, ...)
+{
+ va_list args;
+ uint i;
+ char printbuffer[CFG_PBSIZE];
+
+ va_start(args, fmt);
+ i = vsprintf(printbuffer, fmt, args);
+ va_end(args);
+
+ puts_ll(printbuffer);
+
+ return i;
+}
diff --git a/pbl/string.c b/pbl/string.c
index b773f5cf7c..927c92dc05 100644
--- a/pbl/string.c
+++ b/pbl/string.c
@@ -119,3 +119,17 @@ void *memset(void *s, int c, size_t count)
*xs++ = c;
return s;
}
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count)
+{
+ const char *sc;
+
+ for (sc = s; count-- && *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
diff --git a/scripts/.gitignore b/scripts/.gitignore
index b574b22fb1..6203589fe3 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -22,3 +22,5 @@ bareboximd-target
bareboxstate
bareboxstate-target
mk-am35xx-spi-image
+mxsimage
+mxsboot
diff --git a/scripts/Makefile b/scripts/Makefile
index 5483a64245..74c22136db 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -19,6 +19,11 @@ hostprogs-$(CONFIG_ARCH_S5PCxx) += s5p_cksum
hostprogs-$(CONFIG_ARCH_DAVINCI) += mkublheader
hostprogs-$(CONFIG_ARCH_ZYNQ) += zynq_mkimage
hostprogs-$(CONFIG_ARCH_SOCFPGA) += socfpga_mkimage
+hostprogs-$(CONFIG_ARCH_MXS) += mxsimage mxsboot
+HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl`
+HOSTCFLAGS_mxs-usb-loader.o = `pkg-config --cflags libusb-1.0`
+HOSTLOADLIBES_mxs-usb-loader = `pkg-config --libs libusb-1.0`
+hostprogs-$(CONFIG_ARCH_MXS_USBLOADER) += mxs-usb-loader
subdir-y += mod
subdir-$(CONFIG_OMAP4_USBBOOT) += omap4_usbboot
diff --git a/scripts/mxs-usb-loader.c b/scripts/mxs-usb-loader.c
new file mode 100644
index 0000000000..8529274d6e
--- /dev/null
+++ b/scripts/mxs-usb-loader.c
@@ -0,0 +1,236 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+#include <stdint.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+void put32le(uint8_t * buf, uint32_t i)
+{
+ *buf++ = i & 0xff;
+ *buf++ = (i >> 8) & 0xff;
+ *buf++ = (i >> 16) & 0xff;
+ *buf++ = (i >> 24) & 0xff;
+}
+
+void put32be(uint8_t * buf, uint32_t i)
+{
+ *buf++ = (i >> 24) & 0xff;
+ *buf++ = (i >> 16) & 0xff;
+ *buf++ = (i >> 8) & 0xff;
+ *buf++ = i & 0xff;
+}
+
+enum dev_type_t {
+ HID_DEVICE,
+ RECOVERY_DEVICE,
+};
+
+struct dev_info_t {
+ uint16_t vendor_id;
+ uint16_t product_id;
+ unsigned xfer_size;
+ enum dev_type_t dev_type;
+};
+
+struct dev_info_t g_dev_info[] = {
+ {0x066f, 0x3780, 1024, HID_DEVICE}, /* i.MX233 / STMP3780 */
+ {0x066f, 0x3770, 48, HID_DEVICE}, /* STMP3770 */
+ {0x15A2, 0x004F, 1024, HID_DEVICE}, /* i.MX28 */
+ {0x066f, 0x3600, 4096, RECOVERY_DEVICE}, /* STMP36xx */
+};
+
+int send_hid(libusb_device_handle * dev, int xfer_size, uint8_t * data,
+ int size, int nr_xfers)
+{
+ int i;
+
+ libusb_detach_kernel_driver(dev, 0);
+ libusb_detach_kernel_driver(dev, 4);
+
+ libusb_claim_interface(dev, 0);
+ libusb_claim_interface(dev, 4);
+
+ uint8_t *xfer_buf = malloc(1 + xfer_size);
+ uint8_t *p = xfer_buf;
+
+ *p++ = 0x01; /* Report id */
+
+ /* Command block wrapper */
+ *p++ = 'B'; /* Signature */
+ *p++ = 'L';
+ *p++ = 'T';
+ *p++ = 'C';
+ put32le(p, 0x1); /* Tag */
+ p += 4;
+ put32le(p, size); /* Payload size */
+ p += 4;
+ *p++ = 0; /* Flags (host to device) */
+ p += 2; /* Reserved */
+
+ /* Command descriptor block */
+ *p++ = 0x02; /* Firmware download */
+ put32be(p, size); /* Download size */
+
+ int ret = libusb_control_transfer(dev,
+ LIBUSB_REQUEST_TYPE_CLASS |
+ LIBUSB_RECIPIENT_INTERFACE, 0x9,
+ 0x201, 0,
+ xfer_buf, xfer_size + 1, 1000);
+ if (ret < 0) {
+ printf("transfer error at init step\n");
+ return 1;
+ }
+
+ for (i = 0; i < nr_xfers; i++) {
+ xfer_buf[0] = 0x2;
+ memcpy(&xfer_buf[1], &data[i * xfer_size], xfer_size);
+
+ ret = libusb_control_transfer(dev,
+ LIBUSB_REQUEST_TYPE_CLASS |
+ LIBUSB_RECIPIENT_INTERFACE, 0x9,
+ 0x202, 0, xfer_buf, xfer_size + 1,
+ 1000);
+ if (ret < 0) {
+ printf("transfer error at send step %d\n", i);
+ return 1;
+ }
+ }
+
+ int recv_size;
+ ret =
+ libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size,
+ &recv_size, 1000);
+ if (ret < 0) {
+ printf("transfer error at final stage\n");
+ return 1;
+ }
+
+ return ret;
+}
+
+int send_recovery(libusb_device_handle * dev, int xfer_size, uint8_t * data,
+ int size, int nr_xfers)
+{
+ (void)nr_xfers;
+ // there should be no kernel driver attached but in doubt...
+ libusb_detach_kernel_driver(dev, 0);
+ libusb_claim_interface(dev, 0);
+
+ int sent = 0;
+ while (sent < size) {
+ int xfered;
+ int len = MIN(size - sent, xfer_size);
+ int ret =
+ libusb_bulk_transfer(dev, 1, data + sent, len, &xfered,
+ 1000);
+ if (ret < 0) {
+ printf("transfer error at send offset %d\n", sent);
+ return 1;
+ }
+ if (xfered == 0) {
+ printf("empty transfer at step offset %d\n", sent);
+ return 2;
+ }
+ sent += xfered;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ printf("usage: %s <xfer size> <file>\n", argv[0]);
+ printf
+ ("If <xfer size> is set to zero, the preferred one is used.\n");
+ return 1;
+ }
+
+ char *end;
+ int xfer_size = strtol(argv[1], &end, 0);
+ if (end != (argv[1] + strlen(argv[1]))) {
+ printf("Invalid transfer size !\n");
+ return 1;
+ }
+
+ libusb_device_handle *dev;
+
+ libusb_init(NULL);
+
+ libusb_set_debug(NULL, 3);
+
+ unsigned i;
+ for (i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++) {
+ dev = libusb_open_device_with_vid_pid(NULL,
+ g_dev_info[i].vendor_id,
+ g_dev_info[i].product_id);
+ if (dev == NULL)
+ continue;
+ if (xfer_size == 0)
+ xfer_size = g_dev_info[i].xfer_size;
+ printf("Found a match for %04x:%04x\n",
+ g_dev_info[i].vendor_id, g_dev_info[i].product_id);
+ break;
+ }
+ if (dev == NULL) {
+ printf("Cannot open device\n");
+ return 1;
+ }
+
+ FILE *f = fopen(argv[2], "r");
+ if (f == NULL) {
+ perror("cannot open file");
+ return 1;
+ }
+ fseek(f, 0, SEEK_END);
+ size_t size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ printf("Transfer size: %d\n", xfer_size);
+ int nr_xfers = (size + xfer_size - 1) / xfer_size;
+ uint8_t *file_buf = malloc(nr_xfers * xfer_size);
+ memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff
+ if (fread(file_buf, size, 1, f) != 1) {
+ perror("read error");
+ fclose(f);
+ return 1;
+ }
+ fclose(f);
+
+ switch (g_dev_info[i].dev_type) {
+ case HID_DEVICE:
+ send_hid(dev, xfer_size, file_buf, size, nr_xfers);
+ break;
+ case RECOVERY_DEVICE:
+ send_recovery(dev, xfer_size, file_buf, size, nr_xfers);
+ break;
+ default:
+ printf("unknown device type\n");
+ break;
+ }
+
+ return 0;
+}
diff --git a/scripts/mxsboot.c b/scripts/mxsboot.c
new file mode 100644
index 0000000000..2b90b2561d
--- /dev/null
+++ b/scripts/mxsboot.c
@@ -0,0 +1,641 @@
+/*
+ * Freescale i.MX28 image generator
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "compiler.h"
+
+/*
+ * Default BCB layout.
+ *
+ * TWEAK this if you have blown any OCOTP fuses.
+ */
+#define STRIDE_PAGES 64
+#define STRIDE_COUNT 4
+
+/*
+ * Layout for 256Mb big NAND with 2048b page size, 64b OOB size and
+ * 128kb erase size.
+ *
+ * TWEAK this if you have different kind of NAND chip.
+ */
+static uint32_t nand_writesize = 2048;
+static uint32_t nand_oobsize = 64;
+static uint32_t nand_erasesize = 128 * 1024;
+
+/*
+ * Sector on which the SigmaTel boot partition (0x53) starts.
+ */
+static uint32_t sd_sector = 2048;
+
+/*
+ * Each of the U-Boot bootstreams is at maximum 1MB big.
+ *
+ * TWEAK this if, for some wild reason, you need to boot bigger image.
+ */
+#define MAX_BOOTSTREAM_SIZE (1 * 1024 * 1024)
+
+/* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */
+#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
+#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
+#define MXS_NAND_METADATA_SIZE 10
+#define MXS_NAND_COMMAND_BUFFER_SIZE 32
+
+struct mx28_nand_fcb {
+ uint32_t checksum;
+ uint32_t fingerprint;
+ uint32_t version;
+ struct {
+ uint8_t data_setup;
+ uint8_t data_hold;
+ uint8_t address_setup;
+ uint8_t dsample_time;
+ uint8_t nand_timing_state;
+ uint8_t rea;
+ uint8_t rloh;
+ uint8_t rhoh;
+ } timing;
+ uint32_t page_data_size;
+ uint32_t total_page_size;
+ uint32_t sectors_per_block;
+ uint32_t number_of_nands; /* Ignored */
+ uint32_t total_internal_die; /* Ignored */
+ uint32_t cell_type; /* Ignored */
+ uint32_t ecc_block_n_ecc_type;
+ uint32_t ecc_block_0_size;
+ uint32_t ecc_block_n_size;
+ uint32_t ecc_block_0_ecc_type;
+ uint32_t metadata_bytes;
+ uint32_t num_ecc_blocks_per_page;
+ uint32_t ecc_block_n_ecc_level_sdk; /* Ignored */
+ uint32_t ecc_block_0_size_sdk; /* Ignored */
+ uint32_t ecc_block_n_size_sdk; /* Ignored */
+ uint32_t ecc_block_0_ecc_level_sdk; /* Ignored */
+ uint32_t num_ecc_blocks_per_page_sdk; /* Ignored */
+ uint32_t metadata_bytes_sdk; /* Ignored */
+ uint32_t erase_threshold;
+ uint32_t boot_patch;
+ uint32_t patch_sectors;
+ uint32_t firmware1_starting_sector;
+ uint32_t firmware2_starting_sector;
+ uint32_t sectors_in_firmware1;
+ uint32_t sectors_in_firmware2;
+ uint32_t dbbt_search_area_start_address;
+ uint32_t badblock_marker_byte;
+ uint32_t badblock_marker_start_bit;
+ uint32_t bb_marker_physical_offset;
+};
+
+struct mx28_nand_dbbt {
+ uint32_t checksum;
+ uint32_t fingerprint;
+ uint32_t version;
+ uint32_t number_bb;
+ uint32_t number_2k_pages_bb;
+};
+
+struct mx28_nand_bbt {
+ uint32_t nand;
+ uint32_t number_bb;
+ uint32_t badblock[510];
+};
+
+struct mx28_sd_drive_info {
+ uint32_t chip_num;
+ uint32_t drive_type;
+ uint32_t tag;
+ uint32_t first_sector_number;
+ uint32_t sector_count;
+};
+
+struct mx28_sd_config_block {
+ uint32_t signature;
+ uint32_t primary_boot_tag;
+ uint32_t secondary_boot_tag;
+ uint32_t num_copies;
+ struct mx28_sd_drive_info drv_info[1];
+};
+
+static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
+{
+ return ecc_strength * 13;
+}
+
+static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
+ uint32_t page_oob_size)
+{
+ if (page_data_size == 2048)
+ return 8;
+
+ if (page_data_size == 4096) {
+ if (page_oob_size == 128)
+ return 8;
+
+ if (page_oob_size == 218)
+ return 16;
+ }
+
+ return 0;
+}
+
+static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
+ uint32_t ecc_strength)
+{
+ uint32_t chunk_data_size_in_bits;
+ uint32_t chunk_ecc_size_in_bits;
+ uint32_t chunk_total_size_in_bits;
+ uint32_t block_mark_chunk_number;
+ uint32_t block_mark_chunk_bit_offset;
+ uint32_t block_mark_bit_offset;
+
+ chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
+ chunk_ecc_size_in_bits = mx28_nand_ecc_size_in_bits(ecc_strength);
+
+ chunk_total_size_in_bits =
+ chunk_data_size_in_bits + chunk_ecc_size_in_bits;
+
+ /* Compute the bit offset of the block mark within the physical page. */
+ block_mark_bit_offset = page_data_size * 8;
+
+ /* Subtract the metadata bits. */
+ block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
+
+ /*
+ * Compute the chunk number (starting at zero) in which the block mark
+ * appears.
+ */
+ block_mark_chunk_number =
+ block_mark_bit_offset / chunk_total_size_in_bits;
+
+ /*
+ * Compute the bit offset of the block mark within its chunk, and
+ * validate it.
+ */
+ block_mark_chunk_bit_offset = block_mark_bit_offset -
+ (block_mark_chunk_number * chunk_total_size_in_bits);
+
+ if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
+ return 1;
+
+ /*
+ * Now that we know the chunk number in which the block mark appears,
+ * we can subtract all the ECC bits that appear before it.
+ */
+ block_mark_bit_offset -=
+ block_mark_chunk_number * chunk_ecc_size_in_bits;
+
+ return block_mark_bit_offset;
+}
+
+static inline uint32_t mx28_nand_mark_byte_offset(void)
+{
+ uint32_t ecc_strength;
+ ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
+ return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3;
+}
+
+static inline uint32_t mx28_nand_mark_bit_offset(void)
+{
+ uint32_t ecc_strength;
+ ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
+ return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7;
+}
+
+static uint32_t mx28_nand_block_csum(uint8_t *block, uint32_t size)
+{
+ uint32_t csum = 0;
+ int i;
+
+ for (i = 0; i < size; i++)
+ csum += block[i];
+
+ return csum ^ 0xffffffff;
+}
+
+static struct mx28_nand_fcb *mx28_nand_get_fcb(uint32_t size)
+{
+ struct mx28_nand_fcb *fcb;
+ uint32_t bcb_size_bytes;
+ uint32_t stride_size_bytes;
+ uint32_t bootstream_size_pages;
+ uint32_t fw1_start_page;
+ uint32_t fw2_start_page;
+
+ fcb = malloc(nand_writesize);
+ if (!fcb) {
+ printf("MX28 NAND: Unable to allocate FCB\n");
+ return NULL;
+ }
+
+ memset(fcb, 0, nand_writesize);
+
+ fcb->fingerprint = 0x20424346;
+ fcb->version = 0x01000000;
+
+ /*
+ * FIXME: These here are default values as found in kobs-ng. We should
+ * probably retrieve the data from NAND or something.
+ */
+ fcb->timing.data_setup = 80;
+ fcb->timing.data_hold = 60;
+ fcb->timing.address_setup = 25;
+ fcb->timing.dsample_time = 6;
+
+ fcb->page_data_size = nand_writesize;
+ fcb->total_page_size = nand_writesize + nand_oobsize;
+ fcb->sectors_per_block = nand_erasesize / nand_writesize;
+
+ fcb->num_ecc_blocks_per_page = (nand_writesize / 512) - 1;
+ fcb->ecc_block_0_size = 512;
+ fcb->ecc_block_n_size = 512;
+ fcb->metadata_bytes = 10;
+
+ if (nand_writesize == 2048) {
+ fcb->ecc_block_n_ecc_type = 4;
+ fcb->ecc_block_0_ecc_type = 4;
+ } else if (nand_writesize == 4096) {
+ if (nand_oobsize == 128) {
+ fcb->ecc_block_n_ecc_type = 4;
+ fcb->ecc_block_0_ecc_type = 4;
+ } else if (nand_oobsize == 218) {
+ fcb->ecc_block_n_ecc_type = 8;
+ fcb->ecc_block_0_ecc_type = 8;
+ }
+ }
+
+ if (fcb->ecc_block_n_ecc_type == 0) {
+ printf("MX28 NAND: Unsupported NAND geometry\n");
+ goto err;
+ }
+
+ fcb->boot_patch = 0;
+ fcb->patch_sectors = 0;
+
+ fcb->badblock_marker_byte = mx28_nand_mark_byte_offset();
+ fcb->badblock_marker_start_bit = mx28_nand_mark_bit_offset();
+ fcb->bb_marker_physical_offset = nand_writesize;
+
+ stride_size_bytes = STRIDE_PAGES * nand_writesize;
+ bcb_size_bytes = stride_size_bytes * STRIDE_COUNT;
+
+ bootstream_size_pages = (size + (nand_writesize - 1)) /
+ nand_writesize;
+
+ fw1_start_page = 2 * bcb_size_bytes / nand_writesize;
+ fw2_start_page = (2 * bcb_size_bytes + MAX_BOOTSTREAM_SIZE) /
+ nand_writesize;
+
+ fcb->firmware1_starting_sector = fw1_start_page;
+ fcb->firmware2_starting_sector = fw2_start_page;
+ fcb->sectors_in_firmware1 = bootstream_size_pages;
+ fcb->sectors_in_firmware2 = bootstream_size_pages;
+
+ fcb->dbbt_search_area_start_address = STRIDE_PAGES * STRIDE_COUNT;
+
+ return fcb;
+
+err:
+ free(fcb);
+ return NULL;
+}
+
+static struct mx28_nand_dbbt *mx28_nand_get_dbbt(void)
+{
+ struct mx28_nand_dbbt *dbbt;
+
+ dbbt = malloc(nand_writesize);
+ if (!dbbt) {
+ printf("MX28 NAND: Unable to allocate DBBT\n");
+ return NULL;
+ }
+
+ memset(dbbt, 0, nand_writesize);
+
+ dbbt->fingerprint = 0x54424244;
+ dbbt->version = 0x1;
+
+ return dbbt;
+}
+
+static inline uint8_t mx28_nand_parity_13_8(const uint8_t b)
+{
+ uint32_t parity = 0, tmp;
+
+ tmp = ((b >> 6) ^ (b >> 5) ^ (b >> 3) ^ (b >> 2)) & 1;
+ parity |= tmp << 0;
+
+ tmp = ((b >> 7) ^ (b >> 5) ^ (b >> 4) ^ (b >> 2) ^ (b >> 1)) & 1;
+ parity |= tmp << 1;
+
+ tmp = ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 1) ^ (b >> 0)) & 1;
+ parity |= tmp << 2;
+
+ tmp = ((b >> 7) ^ (b >> 4) ^ (b >> 3) ^ (b >> 0)) & 1;
+ parity |= tmp << 3;
+
+ tmp = ((b >> 6) ^ (b >> 4) ^ (b >> 3) ^
+ (b >> 2) ^ (b >> 1) ^ (b >> 0)) & 1;
+ parity |= tmp << 4;
+
+ return parity;
+}
+
+static uint8_t *mx28_nand_fcb_block(struct mx28_nand_fcb *fcb)
+{
+ uint8_t *block;
+ uint8_t *ecc;
+ int i;
+
+ block = malloc(nand_writesize + nand_oobsize);
+ if (!block) {
+ printf("MX28 NAND: Unable to allocate FCB block\n");
+ return NULL;
+ }
+
+ memset(block, 0, nand_writesize + nand_oobsize);
+
+ /* Update the FCB checksum */
+ fcb->checksum = mx28_nand_block_csum(((uint8_t *)fcb) + 4, 508);
+
+ /* Figure 12-11. in iMX28RM, rev. 1, says FCB is at offset 12 */
+ memcpy(block + 12, fcb, sizeof(struct mx28_nand_fcb));
+
+ /* ECC is at offset 12 + 512 */
+ ecc = block + 12 + 512;
+
+ /* Compute the ECC parity */
+ for (i = 0; i < sizeof(struct mx28_nand_fcb); i++)
+ ecc[i] = mx28_nand_parity_13_8(block[i + 12]);
+
+ return block;
+}
+
+static int mx28_nand_write_fcb(struct mx28_nand_fcb *fcb, uint8_t *buf)
+{
+ uint32_t offset;
+ uint8_t *fcbblock;
+ int ret = 0;
+ int i;
+
+ fcbblock = mx28_nand_fcb_block(fcb);
+ if (!fcbblock)
+ return -1;
+
+ for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
+ offset = i * nand_writesize;
+ memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize);
+ /* Mark the NAND page is OK. */
+ buf[offset + nand_writesize] = 0xff;
+ }
+
+ free(fcbblock);
+ return ret;
+}
+
+static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, uint8_t *buf)
+{
+ uint32_t offset;
+ int i = STRIDE_PAGES * STRIDE_COUNT;
+
+ for (; i < 2 * STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
+ offset = i * nand_writesize;
+ memcpy(buf + offset, dbbt, sizeof(struct mx28_nand_dbbt));
+ }
+
+ return 0;
+}
+
+static int mx28_nand_write_firmware(struct mx28_nand_fcb *fcb, int infd,
+ uint8_t *buf)
+{
+ int ret;
+ off_t size;
+ uint32_t offset1, offset2;
+
+ size = lseek(infd, 0, SEEK_END);
+ lseek(infd, 0, SEEK_SET);
+
+ offset1 = fcb->firmware1_starting_sector * nand_writesize;
+ offset2 = fcb->firmware2_starting_sector * nand_writesize;
+
+ ret = read(infd, buf + offset1, size);
+ if (ret != size)
+ return -1;
+
+ memcpy(buf + offset2, buf + offset1, size);
+
+ return 0;
+}
+
+static void usage(void)
+{
+ printf(
+ "Usage: mxsboot [ops] <type> <infile> <outfile>\n"
+ "Augment BootStream file with a proper header for i.MX28 boot\n"
+ "\n"
+ " <type> type of image:\n"
+ " \"nand\" for NAND image\n"
+ " \"sd\" for SD image\n"
+ " <infile> input file, the u-boot.sb bootstream\n"
+ " <outfile> output file, the bootable image\n"
+ "\n");
+ printf(
+ "For NAND boot, these options are accepted:\n"
+ " -w <size> NAND page size\n"
+ " -o <size> NAND OOB size\n"
+ " -e <size> NAND erase size\n"
+ "\n"
+ "For SD boot, these options are accepted:\n"
+ " -p <sector> Sector where the SGTL partition starts\n"
+ );
+}
+
+static int mx28_create_nand_image(int infd, int outfd)
+{
+ struct mx28_nand_fcb *fcb;
+ struct mx28_nand_dbbt *dbbt;
+ int ret = -1;
+ uint8_t *buf;
+ int size;
+ ssize_t wr_size;
+
+ size = nand_writesize * 512 + 2 * MAX_BOOTSTREAM_SIZE;
+
+ buf = malloc(size);
+ if (!buf) {
+ printf("Can not allocate output buffer of %d bytes\n", size);
+ goto err0;
+ }
+
+ memset(buf, 0, size);
+
+ fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE);
+ if (!fcb) {
+ printf("Unable to compile FCB\n");
+ goto err1;
+ }
+
+ dbbt = mx28_nand_get_dbbt();
+ if (!dbbt) {
+ printf("Unable to compile DBBT\n");
+ goto err2;
+ }
+
+ ret = mx28_nand_write_fcb(fcb, buf);
+ if (ret) {
+ printf("Unable to write FCB to buffer\n");
+ goto err3;
+ }
+
+ ret = mx28_nand_write_dbbt(dbbt, buf);
+ if (ret) {
+ printf("Unable to write DBBT to buffer\n");
+ goto err3;
+ }
+
+ ret = mx28_nand_write_firmware(fcb, infd, buf);
+ if (ret) {
+ printf("Unable to write firmware to buffer\n");
+ goto err3;
+ }
+
+ wr_size = write(outfd, buf, size);
+ if (wr_size != size) {
+ ret = -1;
+ goto err3;
+ }
+
+ ret = 0;
+
+err3:
+ free(dbbt);
+err2:
+ free(fcb);
+err1:
+ free(buf);
+err0:
+ return ret;
+}
+
+static int mx28_create_sd_image(int infd, int outfd)
+{
+ int ret = -1;
+ uint32_t *buf;
+ int size;
+ off_t fsize;
+ ssize_t wr_size;
+ struct mx28_sd_config_block *cb;
+
+ fsize = lseek(infd, 0, SEEK_END);
+ lseek(infd, 0, SEEK_SET);
+ size = fsize + 4 * 512;
+
+ buf = malloc(size);
+ if (!buf) {
+ printf("Can not allocate output buffer of %d bytes\n", size);
+ goto err0;
+ }
+
+ ret = read(infd, (uint8_t *)buf + 4 * 512, fsize);
+ if (ret != fsize) {
+ ret = -1;
+ goto err1;
+ }
+
+ cb = (struct mx28_sd_config_block *)buf;
+
+ cb->signature = 0x00112233;
+ cb->primary_boot_tag = 0x1;
+ cb->secondary_boot_tag = 0x1;
+ cb->num_copies = 1;
+ cb->drv_info[0].chip_num = 0x0;
+ cb->drv_info[0].drive_type = 0x0;
+ cb->drv_info[0].tag = 0x1;
+ cb->drv_info[0].first_sector_number = sd_sector + 4;
+ cb->drv_info[0].sector_count = (size - 4) / 512;
+
+ wr_size = write(outfd, buf, size);
+ if (wr_size != size) {
+ ret = -1;
+ goto err1;
+ }
+
+ ret = 0;
+
+err1:
+ free(buf);
+err0:
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int infd, outfd;
+ int ret = 0;
+ int opt;
+ int sdimage = 0;
+
+ while ((opt = getopt(argc, argv, "w:o:e:p:")) != -1) {
+ switch (opt) {
+ case 'w':
+ nand_writesize = strtoul(optarg, NULL, 0);
+ break;
+ case 'o':
+ nand_oobsize = strtoul(optarg, NULL, 0);
+ break;
+ case 'e':
+ nand_erasesize = strtoul(optarg, NULL, 0);
+ break;
+ case 'p':
+ sd_sector = strtoul(optarg, NULL, 0);
+ break;
+ }
+ }
+
+ if (argc - optind < 3) {
+ usage();
+ ret = 1;
+ goto err1;
+ }
+
+ if (!strcmp(argv[optind], "sd"))
+ sdimage = 1;
+ else if (strcmp(argv[optind], "nand"))
+ return -1;
+
+ infd = open(argv[optind + 1], O_RDONLY);
+ if (infd < 0) {
+ printf("Input BootStream file can not be opened\n");
+ ret = 2;
+ goto err1;
+ }
+
+ outfd = open(argv[optind + 2], O_CREAT | O_TRUNC | O_WRONLY,
+ S_IRUSR | S_IWUSR);
+ if (outfd < 0) {
+ printf("Output file can not be created\n");
+ ret = 3;
+ goto err2;
+ }
+
+ if (sdimage)
+ ret = mx28_create_sd_image(infd, outfd);
+ else
+ ret = mx28_create_nand_image(infd, outfd);
+
+ close(outfd);
+err2:
+ close(infd);
+err1:
+ return ret;
+}
diff --git a/scripts/mxsimage.c b/scripts/mxsimage.c
new file mode 100644
index 0000000000..0a5f6a05ef
--- /dev/null
+++ b/scripts/mxsimage.c
@@ -0,0 +1,2561 @@
+/*
+ * Freescale i.MX23/i.MX28 SB image generator
+ *
+ * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <openssl/evp.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+
+#define SB_BLOCK_SIZE 16
+
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static char *prepfile;
+static char *bootloaderfile;
+
+struct sb_boot_image_version {
+ uint16_t major;
+ uint16_t pad0;
+ uint16_t minor;
+ uint16_t pad1;
+ uint16_t revision;
+ uint16_t pad2;
+};
+
+struct sb_boot_image_header {
+ union {
+ /* SHA1 of the header. */
+ uint8_t digest[20];
+ struct {
+ /* CBC-MAC initialization vector. */
+ uint8_t iv[16];
+ uint8_t extra[4];
+ };
+ };
+ /* 'STMP' */
+ uint8_t signature1[4];
+ /* Major version of the image format. */
+ uint8_t major_version;
+ /* Minor version of the image format. */
+ uint8_t minor_version;
+ /* Flags associated with the image. */
+ uint16_t flags;
+ /* Size of the image in 16b blocks. */
+ uint32_t image_blocks;
+ /* Offset of the first tag in 16b blocks. */
+ uint32_t first_boot_tag_block;
+ /* ID of the section to boot from. */
+ uint32_t first_boot_section_id;
+ /* Amount of crypto keys. */
+ uint16_t key_count;
+ /* Offset to the key dictionary in 16b blocks. */
+ uint16_t key_dictionary_block;
+ /* Size of this header in 16b blocks. */
+ uint16_t header_blocks;
+ /* Amount of section headers. */
+ uint16_t section_count;
+ /* Section header size in 16b blocks. */
+ uint16_t section_header_size;
+ /* Padding to align timestamp to uint64_t. */
+ uint8_t padding0[2];
+ /* 'sgtl' (since v1.1) */
+ uint8_t signature2[4];
+ /* Image generation date, in microseconds since 1.1.2000 . */
+ uint64_t timestamp_us;
+ /* Product version. */
+ struct sb_boot_image_version
+ product_version;
+ /* Component version. */
+ struct sb_boot_image_version
+ component_version;
+ /* Drive tag for the system drive. (since v1.1) */
+ uint16_t drive_tag;
+ /* Padding. */
+ uint8_t padding1[6];
+};
+
+#define SB_VERSION_MAJOR 1
+#define SB_VERSION_MINOR 1
+
+/* Enable to HTLLC verbose boot report. */
+#define SB_IMAGE_FLAG_VERBOSE (1 << 0)
+
+struct sb_key_dictionary_key {
+ /* The CBC-MAC of image and sections header. */
+ uint8_t cbc_mac[SB_BLOCK_SIZE];
+ /* The AES key encrypted by image key (zero). */
+ uint8_t key[SB_BLOCK_SIZE];
+};
+
+struct sb_ivt_header {
+ uint32_t header;
+ uint32_t entry;
+ uint32_t reserved1;
+ uint32_t dcd;
+ uint32_t boot_data;
+ uint32_t self;
+ uint32_t csf;
+ uint32_t reserved2;
+};
+
+#define SB_HAB_IVT_TAG 0xd1UL
+#define SB_HAB_DCD_TAG 0xd2UL
+
+#define SB_HAB_VERSION 0x40UL
+
+/*
+ * The "size" field in the IVT header is not naturally aligned,
+ * use this macro to fill first 4 bytes of the IVT header without
+ * causing issues on some systems (esp. M68k, PPC, MIPS-BE, ARM-BE).
+ */
+static inline uint32_t sb_hab_ivt_header(void)
+{
+ uint32_t ret = 0;
+ ret |= SB_HAB_IVT_TAG << 24;
+ ret |= sizeof(struct sb_ivt_header) << 16;
+ ret |= SB_HAB_VERSION;
+ return htonl(ret);
+}
+
+struct sb_sections_header {
+ /* Section number. */
+ uint32_t section_number;
+ /* Offset of this sections first instruction after "TAG". */
+ uint32_t section_offset;
+ /* Size of the section in 16b blocks. */
+ uint32_t section_size;
+ /* Section flags. */
+ uint32_t section_flags;
+};
+
+#define SB_SECTION_FLAG_BOOTABLE (1 << 0)
+
+struct sb_command {
+ struct {
+ uint8_t checksum;
+ uint8_t tag;
+ uint16_t flags;
+#define ROM_TAG_CMD_FLAG_ROM_LAST_TAG 0x1
+#define ROM_LOAD_CMD_FLAG_DCD_LOAD 0x1 /* MX28 only */
+#define ROM_JUMP_CMD_FLAG_HAB 0x1 /* MX28 only */
+#define ROM_CALL_CMD_FLAG_HAB 0x1 /* MX28 only */
+ } header;
+
+ union {
+ struct {
+ uint32_t reserved[3];
+ } nop;
+ struct {
+ uint32_t section_number;
+ uint32_t section_length;
+ uint32_t section_flags;
+ } tag;
+ struct {
+ uint32_t address;
+ uint32_t count;
+ uint32_t crc32;
+ } load;
+ struct {
+ uint32_t address;
+ uint32_t count;
+ uint32_t pattern;
+ } fill;
+ struct {
+ uint32_t address;
+ uint32_t reserved;
+ /* Passed in register r0 before JUMP */
+ uint32_t argument;
+ } jump;
+ struct {
+ uint32_t address;
+ uint32_t reserved;
+ /* Passed in register r0 before CALL */
+ uint32_t argument;
+ } call;
+ struct {
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t mode;
+ } mode;
+
+ };
+};
+
+/*
+ * Most of the mode names are same or at least similar
+ * on i.MX23 and i.MX28, but some of the mode names
+ * differ. The "name" field represents the mode name
+ * on i.MX28 as seen in Table 12-2 of the datasheet.
+ * The "altname" field represents the differently named
+ * fields on i.MX23 as seen in Table 35-3 of the
+ * datasheet.
+ */
+static const struct {
+ const char *name;
+ const char *altname;
+ const uint8_t mode;
+} modetable[] = {
+ { "USB", NULL, 0x00 },
+ { "I2C", NULL, 0x01 },
+ { "SPI2_FLASH", "SPI1_FLASH", 0x02 },
+ { "SPI3_FLASH", "SPI2_FLASH", 0x03 },
+ { "NAND_BCH", NULL, 0x04 },
+ { "JTAG", NULL, 0x06 },
+ { "SPI3_EEPROM", "SPI2_EEPROM", 0x08 },
+ { "SD_SSP0", NULL, 0x09 },
+ { "SD_SSP1", NULL, 0x0A }
+};
+
+enum sb_tag {
+ ROM_NOP_CMD = 0x00,
+ ROM_TAG_CMD = 0x01,
+ ROM_LOAD_CMD = 0x02,
+ ROM_FILL_CMD = 0x03,
+ ROM_JUMP_CMD = 0x04,
+ ROM_CALL_CMD = 0x05,
+ ROM_MODE_CMD = 0x06
+};
+
+struct sb_source_entry {
+ uint8_t tag;
+ uint32_t address;
+ uint32_t flags;
+ char *filename;
+};
+
+/*
+ * DCD block
+ * |-Write to address command block
+ * | 0xf00 == 0xf33d
+ * | 0xba2 == 0xb33f
+ * |-ORR address with mask command block
+ * | 0xf00 |= 0x1337
+ * |-Write to address command block
+ * | 0xba2 == 0xd00d
+ * :
+ */
+#define SB_HAB_DCD_WRITE 0xccUL
+#define SB_HAB_DCD_CHECK 0xcfUL
+#define SB_HAB_DCD_NOOP 0xc0UL
+#define SB_HAB_DCD_MASK_BIT (1 << 3)
+#define SB_HAB_DCD_SET_BIT (1 << 4)
+
+/* Addr.n = Value.n */
+#define SB_DCD_WRITE \
+ (SB_HAB_DCD_WRITE << 24)
+/* Addr.n &= ~Value.n */
+#define SB_DCD_ANDC \
+ ((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT)
+/* Addr.n |= Value.n */
+#define SB_DCD_ORR \
+ ((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT)
+/* (Addr.n & Value.n) == 0 */
+#define SB_DCD_CHK_EQZ \
+ (SB_HAB_DCD_CHECK << 24)
+/* (Addr.n & Value.n) == Value.n */
+#define SB_DCD_CHK_EQ \
+ ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT)
+/* (Addr.n & Value.n) != Value.n */
+#define SB_DCD_CHK_NEQ \
+ ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_MASK_BIT)
+/* (Addr.n & Value.n) != 0 */
+#define SB_DCD_CHK_NEZ \
+ ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT)
+/* NOP */
+#define SB_DCD_NOOP \
+ (SB_HAB_DCD_NOOP << 24)
+
+struct sb_dcd_ctx {
+ struct sb_dcd_ctx *dcd;
+
+ uint32_t id;
+
+ /* The DCD block. */
+ uint32_t *payload;
+ /* Size of the whole DCD block. */
+ uint32_t size;
+
+ /* Pointer to previous DCD command block. */
+ uint32_t *prev_dcd_head;
+};
+
+/*
+ * IMAGE
+ * |-SECTION
+ * | |-CMD
+ * | |-CMD
+ * | `-CMD
+ * |-SECTION
+ * | |-CMD
+ * : :
+ */
+struct sb_cmd_list {
+ char *cmd;
+ size_t len;
+ unsigned int lineno;
+};
+
+struct sb_cmd_ctx {
+ uint32_t size;
+
+ struct sb_cmd_ctx *cmd;
+
+ uint8_t *data;
+ uint32_t length;
+
+ struct sb_command payload;
+ struct sb_command c_payload;
+};
+
+struct sb_section_ctx {
+ uint32_t size;
+
+ /* Section flags */
+ unsigned int boot:1;
+
+ struct sb_section_ctx *sect;
+
+ struct sb_cmd_ctx *cmd_head;
+ struct sb_cmd_ctx *cmd_tail;
+
+ struct sb_sections_header payload;
+};
+
+struct sb_image_ctx {
+ unsigned int in_section:1;
+ unsigned int in_dcd:1;
+ /* Image configuration */
+ unsigned int verbose_boot:1;
+ unsigned int silent_dump:1;
+ const char *input_filename;
+ const char *output_filename;
+ const char *cfg_filename;
+ uint8_t image_key[16];
+
+ /* Number of section in the image */
+ unsigned int sect_count;
+ /* Bootable section */
+ unsigned int sect_boot;
+ unsigned int sect_boot_found:1;
+
+ struct sb_section_ctx *sect_head;
+ struct sb_section_ctx *sect_tail;
+
+ struct sb_dcd_ctx *dcd_head;
+ struct sb_dcd_ctx *dcd_tail;
+
+ EVP_CIPHER_CTX cipher_ctx;
+ EVP_MD_CTX md_ctx;
+ uint8_t digest[32];
+ struct sb_key_dictionary_key sb_dict_key;
+
+ struct sb_boot_image_header payload;
+};
+
+/*
+ * Instruction semantics:
+ * NOOP
+ * TAG [LAST]
+ * LOAD address file
+ * LOAD IVT address IVT_entry_point
+ * FILL address pattern length
+ * JUMP [HAB] address [r0_arg]
+ * CALL [HAB] address [r0_arg]
+ * MODE mode
+ * For i.MX23, mode = USB/I2C/SPI1_FLASH/SPI2_FLASH/NAND_BCH
+ * JTAG/SPI3_EEPROM/SD_SSP0/SD_SSP1
+ * For i.MX28, mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH
+ * JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1
+ */
+
+static uint32_t crc_table[256];
+static int crc_table_valid;
+
+static void make_crc_table(void)
+{
+ uint32_t mask;
+ int i, j;
+ uint32_t poly; /* polynomial exclusive-or pattern */
+
+ if (crc_table_valid)
+ return;
+
+ /*
+ * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10
+ * + x11 + x12 + x16 + x22 + x23 + x26 + x32.
+ */
+ poly = 0x04c11db7;
+
+ for (i = 0; i < 256; i++) {
+ mask = i << 24;
+ for (j = 0; j < 8; j++) {
+ if (mask & 0x80000000)
+ mask = (mask << 1) ^ poly;
+ else
+ mask <<= 1;
+ }
+ crc_table[i] = mask;
+ }
+
+ crc_table_valid = 1;
+}
+
+uint32_t pbl_crc32(uint32_t in_crc, const char *buf, uint32_t len)
+{
+ uint32_t crc32_val;
+ int i;
+
+ make_crc_table();
+
+ crc32_val = ~in_crc;
+
+ for (i = 0; i < len; i++)
+ crc32_val = (crc32_val << 8) ^
+ crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)];
+
+ return crc32_val;
+}
+/*
+ * AES libcrypto
+ */
+static int sb_aes_init(struct sb_image_ctx *ictx, uint8_t *iv, int enc)
+{
+ EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx;
+ int ret;
+
+ /* If there is no init vector, init vector is all zeroes. */
+ if (!iv)
+ iv = ictx->image_key;
+
+ EVP_CIPHER_CTX_init(ctx);
+ ret = EVP_CipherInit(ctx, EVP_aes_128_cbc(), ictx->image_key, iv, enc);
+ if (ret == 1)
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ return ret;
+}
+
+static int sb_aes_crypt(struct sb_image_ctx *ictx, uint8_t *in_data,
+ uint8_t *out_data, int in_len)
+{
+ EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx;
+ int ret, outlen;
+ uint8_t *outbuf;
+
+ outbuf = malloc(in_len);
+ if (!outbuf)
+ return -ENOMEM;
+ memset(outbuf, 0, sizeof(in_len));
+
+ ret = EVP_CipherUpdate(ctx, outbuf, &outlen, in_data, in_len);
+ if (!ret) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (out_data)
+ memcpy(out_data, outbuf, outlen);
+
+err:
+ free(outbuf);
+ return ret;
+}
+
+static int sb_aes_deinit(EVP_CIPHER_CTX *ctx)
+{
+ return EVP_CIPHER_CTX_cleanup(ctx);
+}
+
+static int sb_aes_reinit(struct sb_image_ctx *ictx, int enc)
+{
+ int ret;
+ EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx;
+ struct sb_boot_image_header *sb_header = &ictx->payload;
+ uint8_t *iv = sb_header->iv;
+
+ ret = sb_aes_deinit(ctx);
+ if (!ret)
+ return ret;
+ return sb_aes_init(ictx, iv, enc);
+}
+
+/*
+ * Debug
+ */
+static void soprintf(struct sb_image_ctx *ictx, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (ictx->silent_dump)
+ return;
+
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Code
+ */
+static time_t sb_get_timestamp(void)
+{
+ struct tm time_2000 = {
+ .tm_yday = 1, /* Jan. 1st */
+ .tm_year = 100, /* 2000 */
+ };
+ time_t seconds_to_2000 = mktime(&time_2000);
+ time_t seconds_to_now = time(NULL);
+
+ return seconds_to_now - seconds_to_2000;
+}
+
+static int sb_get_time(time_t time, struct tm *tm)
+{
+ struct tm time_2000 = {
+ .tm_yday = 1, /* Jan. 1st */
+ .tm_year = 0, /* 1900 */
+ };
+ const time_t seconds_to_2000 = mktime(&time_2000);
+ const time_t seconds_to_now = seconds_to_2000 + time;
+ struct tm *ret;
+ ret = gmtime_r(&seconds_to_now, tm);
+ return ret ? 0 : -EINVAL;
+}
+
+static void sb_encrypt_sb_header(struct sb_image_ctx *ictx)
+{
+ EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+ struct sb_boot_image_header *sb_header = &ictx->payload;
+ uint8_t *sb_header_ptr = (uint8_t *)sb_header;
+
+ /* Encrypt the header, compute the digest. */
+ sb_aes_crypt(ictx, sb_header_ptr, NULL, sizeof(*sb_header));
+ EVP_DigestUpdate(md_ctx, sb_header_ptr, sizeof(*sb_header));
+}
+
+static void sb_encrypt_sb_sections_header(struct sb_image_ctx *ictx)
+{
+ EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+ struct sb_section_ctx *sctx = ictx->sect_head;
+ struct sb_sections_header *shdr;
+ uint8_t *sb_sections_header_ptr;
+ const int size = sizeof(*shdr);
+
+ while (sctx) {
+ shdr = &sctx->payload;
+ sb_sections_header_ptr = (uint8_t *)shdr;
+
+ sb_aes_crypt(ictx, sb_sections_header_ptr,
+ ictx->sb_dict_key.cbc_mac, size);
+ EVP_DigestUpdate(md_ctx, sb_sections_header_ptr, size);
+
+ sctx = sctx->sect;
+ };
+}
+
+static void sb_encrypt_key_dictionary_key(struct sb_image_ctx *ictx)
+{
+ EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+
+ sb_aes_crypt(ictx, ictx->image_key, ictx->sb_dict_key.key,
+ sizeof(ictx->sb_dict_key.key));
+ EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key));
+}
+
+static void sb_decrypt_key_dictionary_key(struct sb_image_ctx *ictx)
+{
+ EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+
+ EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key));
+ sb_aes_crypt(ictx, ictx->sb_dict_key.key, ictx->image_key,
+ sizeof(ictx->sb_dict_key.key));
+}
+
+static void sb_encrypt_tag(struct sb_image_ctx *ictx,
+ struct sb_cmd_ctx *cctx)
+{
+ EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+ struct sb_command *cmd = &cctx->payload;
+
+ sb_aes_crypt(ictx, (uint8_t *)cmd,
+ (uint8_t *)&cctx->c_payload, sizeof(*cmd));
+ EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd));
+}
+
+static int sb_encrypt_image(struct sb_image_ctx *ictx)
+{
+ /* Start image-wide crypto. */
+ EVP_MD_CTX_init(&ictx->md_ctx);
+ EVP_DigestInit(&ictx->md_ctx, EVP_sha1());
+
+ /*
+ * SB image header.
+ */
+ sb_aes_init(ictx, NULL, 1);
+ sb_encrypt_sb_header(ictx);
+
+ /*
+ * SB sections header.
+ */
+ sb_encrypt_sb_sections_header(ictx);
+
+ /*
+ * Key dictionary.
+ */
+ sb_aes_reinit(ictx, 1);
+ sb_encrypt_key_dictionary_key(ictx);
+
+ /*
+ * Section tags.
+ */
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ struct sb_section_ctx *sctx = ictx->sect_head;
+
+ while (sctx) {
+ cctx = sctx->cmd_head;
+
+ sb_aes_reinit(ictx, 1);
+
+ while (cctx) {
+ ccmd = &cctx->payload;
+
+ sb_encrypt_tag(ictx, cctx);
+
+ if (ccmd->header.tag == ROM_TAG_CMD) {
+ sb_aes_reinit(ictx, 1);
+ } else if (ccmd->header.tag == ROM_LOAD_CMD) {
+ sb_aes_crypt(ictx, cctx->data, cctx->data,
+ cctx->length);
+ EVP_DigestUpdate(&ictx->md_ctx, cctx->data,
+ cctx->length);
+ }
+
+ cctx = cctx->cmd;
+ }
+
+ sctx = sctx->sect;
+ };
+
+ /*
+ * Dump the SHA1 of the whole image.
+ */
+ sb_aes_reinit(ictx, 1);
+
+ EVP_DigestFinal(&ictx->md_ctx, ictx->digest, NULL);
+ sb_aes_crypt(ictx, ictx->digest, ictx->digest, sizeof(ictx->digest));
+
+ /* Stop the encryption session. */
+ sb_aes_deinit(&ictx->cipher_ctx);
+
+ return 0;
+}
+
+static int sb_load_file(struct sb_cmd_ctx *cctx, const char *filename)
+{
+ long real_size, roundup_size;
+ uint8_t *data;
+ long ret;
+ unsigned long size;
+ FILE *fp;
+
+ if (!filename) {
+ fprintf(stderr, "ERR: Missing filename!\n");
+ return -EINVAL;
+ }
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ goto err_open;
+
+ ret = fseek(fp, 0, SEEK_END);
+ if (ret < 0)
+ goto err_file;
+
+ real_size = ftell(fp);
+ if (real_size < 0)
+ goto err_file;
+
+ ret = fseek(fp, 0, SEEK_SET);
+ if (ret < 0)
+ goto err_file;
+
+ roundup_size = roundup(real_size, SB_BLOCK_SIZE);
+ data = calloc(1, roundup_size);
+ if (!data)
+ goto err_file;
+
+ size = fread(data, 1, real_size, fp);
+ if (size != (unsigned long)real_size)
+ goto err_alloc;
+
+ cctx->data = data;
+ cctx->length = roundup_size;
+
+ fclose(fp);
+ return 0;
+
+err_alloc:
+ free(data);
+err_file:
+ fclose(fp);
+err_open:
+ fprintf(stderr, "ERR: Failed to load file \"%s\"\n", filename);
+ return -EINVAL;
+}
+
+static uint8_t sb_command_checksum(struct sb_command *inst)
+{
+ uint8_t *inst_ptr = (uint8_t *)inst;
+ uint8_t csum = 0;
+ unsigned int i;
+
+ for (i = 0; i < sizeof(struct sb_command); i++)
+ csum += inst_ptr[i];
+
+ return csum;
+}
+
+static int sb_token_to_long(char *tok, uint32_t *rid)
+{
+ char *endptr;
+ unsigned long id;
+
+ if (tok[0] != '0' || tok[1] != 'x') {
+ fprintf(stderr, "ERR: Invalid hexadecimal number!\n");
+ return -EINVAL;
+ }
+
+ tok += 2;
+
+ errno = 0;
+ id = strtoul(tok, &endptr, 16);
+ if ((errno == ERANGE && id == ULONG_MAX) || (errno != 0 && id == 0)) {
+ fprintf(stderr, "ERR: Value can't be decoded!\n");
+ return -EINVAL;
+ }
+
+ /* Check for 32-bit overflow. */
+ if (id > 0xffffffff) {
+ fprintf(stderr, "ERR: Value too big!\n");
+ return -EINVAL;
+ }
+
+ if (endptr == tok) {
+ fprintf(stderr, "ERR: Deformed value!\n");
+ return -EINVAL;
+ }
+
+ *rid = (uint32_t)id;
+ return 0;
+}
+
+static int sb_grow_dcd(struct sb_dcd_ctx *dctx, unsigned int inc_size)
+{
+ uint32_t *tmp;
+
+ if (!inc_size)
+ return 0;
+
+ dctx->size += inc_size;
+ tmp = realloc(dctx->payload, dctx->size);
+ if (!tmp)
+ return -ENOMEM;
+
+ dctx->payload = tmp;
+
+ /* Assemble and update the HAB DCD header. */
+ dctx->payload[0] = htonl((SB_HAB_DCD_TAG << 24) |
+ (dctx->size << 8) |
+ SB_HAB_VERSION);
+
+ return 0;
+}
+
+static int sb_build_dcd(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
+{
+ struct sb_dcd_ctx *dctx;
+
+ char *tok;
+ uint32_t id;
+ int ret;
+
+ dctx = calloc(1, sizeof(*dctx));
+ if (!dctx)
+ return -ENOMEM;
+
+ ret = sb_grow_dcd(dctx, 4);
+ if (ret)
+ goto err_dcd;
+
+ /* Read DCD block number. */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: DCD block without number!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err_dcd;
+ }
+
+ /* Parse the DCD block number. */
+ ret = sb_token_to_long(tok, &id);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Malformed DCD block number!\n",
+ cmd->lineno);
+ goto err_dcd;
+ }
+
+ dctx->id = id;
+
+ /*
+ * The DCD block is now constructed. Append it to the list.
+ * WARNING: The DCD size is still not computed and will be
+ * updated while parsing it's commands.
+ */
+ if (!ictx->dcd_head) {
+ ictx->dcd_head = dctx;
+ ictx->dcd_tail = dctx;
+ } else {
+ ictx->dcd_tail->dcd = dctx;
+ ictx->dcd_tail = dctx;
+ }
+
+ return 0;
+
+err_dcd:
+ free(dctx->payload);
+ free(dctx);
+ return ret;
+}
+
+static int sb_build_dcd_block(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd,
+ uint32_t type)
+{
+ char *tok;
+ uint32_t address, value, length;
+ int ret;
+
+ struct sb_dcd_ctx *dctx = ictx->dcd_tail;
+ uint32_t *dcd;
+
+ if (dctx->prev_dcd_head && (type != SB_DCD_NOOP) &&
+ ((dctx->prev_dcd_head[0] & 0xff0000ff) == type)) {
+ /* Same instruction as before, just append it. */
+ ret = sb_grow_dcd(dctx, 8);
+ if (ret)
+ return ret;
+ } else if (type == SB_DCD_NOOP) {
+ ret = sb_grow_dcd(dctx, 4);
+ if (ret)
+ return ret;
+
+ /* Update DCD command block pointer. */
+ dctx->prev_dcd_head = dctx->payload +
+ dctx->size / sizeof(*dctx->payload) - 1;
+
+ /* NOOP has only 4 bytes and no payload. */
+ goto noop;
+ } else {
+ /*
+ * Either a different instruction block started now
+ * or this is the first instruction block.
+ */
+ ret = sb_grow_dcd(dctx, 12);
+ if (ret)
+ return ret;
+
+ /* Update DCD command block pointer. */
+ dctx->prev_dcd_head = dctx->payload +
+ dctx->size / sizeof(*dctx->payload) - 3;
+ }
+
+ dcd = dctx->payload + dctx->size / sizeof(*dctx->payload) - 2;
+
+ /*
+ * Prepare the command.
+ */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing DCD address!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Read DCD destination address. */
+ ret = sb_token_to_long(tok, &address);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect DCD address!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ tok = strtok(NULL, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing DCD value!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Read DCD operation value. */
+ ret = sb_token_to_long(tok, &value);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect DCD value!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ /* Fill in the new DCD entry. */
+ dcd[0] = htonl(address);
+ dcd[1] = htonl(value);
+
+noop:
+ /* Update the DCD command block. */
+ length = dctx->size -
+ ((dctx->prev_dcd_head - dctx->payload) *
+ sizeof(*dctx->payload));
+ dctx->prev_dcd_head[0] = htonl(type | (length << 8));
+
+err:
+ return ret;
+}
+
+static int sb_build_section(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
+{
+ struct sb_section_ctx *sctx;
+ struct sb_sections_header *shdr;
+ char *tok;
+ uint32_t bootable = 0;
+ uint32_t id;
+ int ret;
+
+ sctx = calloc(1, sizeof(*sctx));
+ if (!sctx)
+ return -ENOMEM;
+
+ /* Read section number. */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Section without number!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err_sect;
+ }
+
+ /* Parse the section number. */
+ ret = sb_token_to_long(tok, &id);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Malformed section number!\n",
+ cmd->lineno);
+ goto err_sect;
+ }
+
+ /* Read section's BOOTABLE flag. */
+ tok = strtok(NULL, " ");
+ if (tok && (strlen(tok) == 8) && !strncmp(tok, "BOOTABLE", 8))
+ bootable = SB_SECTION_FLAG_BOOTABLE;
+
+ sctx->boot = bootable;
+
+ shdr = &sctx->payload;
+ shdr->section_number = id;
+ shdr->section_flags = bootable;
+
+ /*
+ * The section is now constructed. Append it to the list.
+ * WARNING: The section size is still not computed and will
+ * be updated while parsing it's commands.
+ */
+ ictx->sect_count++;
+
+ /* Mark that this section is bootable one. */
+ if (bootable) {
+ if (ictx->sect_boot_found) {
+ fprintf(stderr,
+ "#%i WARN: Multiple bootable section!\n",
+ cmd->lineno);
+ } else {
+ ictx->sect_boot = id;
+ ictx->sect_boot_found = 1;
+ }
+ }
+
+ if (!ictx->sect_head) {
+ ictx->sect_head = sctx;
+ ictx->sect_tail = sctx;
+ } else {
+ ictx->sect_tail->sect = sctx;
+ ictx->sect_tail = sctx;
+ }
+
+ return 0;
+
+err_sect:
+ free(sctx);
+ return ret;
+}
+
+static int sb_build_command_nop(struct sb_image_ctx *ictx)
+{
+ struct sb_section_ctx *sctx = ictx->sect_tail;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+
+ ccmd = &cctx->payload;
+
+ /*
+ * Construct the command.
+ */
+ ccmd->header.checksum = 0x5a;
+ ccmd->header.tag = ROM_NOP_CMD;
+
+ cctx->size = sizeof(*ccmd);
+
+ /*
+ * Append the command to the last section.
+ */
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ return 0;
+}
+
+static int sb_build_command_tag(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd)
+{
+ struct sb_section_ctx *sctx = ictx->sect_tail;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ char *tok;
+
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+
+ ccmd = &cctx->payload;
+
+ /*
+ * Prepare the command.
+ */
+ /* Check for the LAST keyword. */
+ tok = strtok(cmd->cmd, " ");
+ if (tok && !strcmp(tok, "LAST"))
+ ccmd->header.flags = ROM_TAG_CMD_FLAG_ROM_LAST_TAG;
+
+ /*
+ * Construct the command.
+ */
+ ccmd->header.checksum = 0x5a;
+ ccmd->header.tag = ROM_TAG_CMD;
+
+ cctx->size = sizeof(*ccmd);
+
+ /*
+ * Append the command to the last section.
+ */
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ return 0;
+}
+
+static int sb_build_command_load(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd)
+{
+ struct sb_section_ctx *sctx = ictx->sect_tail;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ char *tok;
+ int ret, is_ivt = 0, is_dcd = 0;
+ uint32_t dest, dcd = 0;
+
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+
+ ccmd = &cctx->payload;
+
+ /*
+ * Prepare the command.
+ */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing LOAD address or 'IVT'!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Check for "IVT" flag. */
+ if (!strcmp(tok, "IVT"))
+ is_ivt = 1;
+ if (!strcmp(tok, "DCD"))
+ is_dcd = 1;
+ if (is_ivt || is_dcd) {
+ tok = strtok(NULL, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing LOAD address!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ /* Read load destination address. */
+ ret = sb_token_to_long(tok, &dest);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect LOAD address!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ /* Read filename or IVT entrypoint or DCD block ID. */
+ tok = strtok(NULL, " ");
+ if (!tok) {
+ fprintf(stderr,
+ "#%i ERR: Missing LOAD filename or IVT ep or DCD block ID!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (is_ivt) {
+ /* Handle IVT. */
+ struct sb_ivt_header *ivt;
+ uint32_t ivtep;
+ ret = sb_token_to_long(tok, &ivtep);
+
+ if (ret) {
+ fprintf(stderr,
+ "#%i ERR: Incorrect IVT entry point!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ ivt = calloc(1, sizeof(*ivt));
+ if (!ivt) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ivt->header = sb_hab_ivt_header();
+ ivt->entry = ivtep;
+ ivt->self = dest;
+
+ cctx->data = (uint8_t *)ivt;
+ cctx->length = sizeof(*ivt);
+ } else if (is_dcd) {
+ struct sb_dcd_ctx *dctx = ictx->dcd_head;
+ uint32_t dcdid;
+ uint8_t *payload;
+ uint32_t asize;
+ ret = sb_token_to_long(tok, &dcdid);
+
+ if (ret) {
+ fprintf(stderr,
+ "#%i ERR: Incorrect DCD block ID!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ while (dctx) {
+ if (dctx->id == dcdid)
+ break;
+ dctx = dctx->dcd;
+ }
+
+ if (!dctx) {
+ fprintf(stderr, "#%i ERR: DCD block %08x not found!\n",
+ cmd->lineno, dcdid);
+ goto err;
+ }
+
+ asize = roundup(dctx->size, SB_BLOCK_SIZE);
+ payload = calloc(1, asize);
+ if (!payload) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(payload, dctx->payload, dctx->size);
+
+ cctx->data = payload;
+ cctx->length = asize;
+
+ /* Set the Load DCD flag. */
+ dcd = ROM_LOAD_CMD_FLAG_DCD_LOAD;
+ } else {
+ const char *loadfile;
+
+ /* Regular LOAD of a file. */
+ if (!strcmp(tok, "@PREP@"))
+ loadfile = prepfile;
+ else if (!strcmp(tok, "@BOOTLOADER@"))
+ loadfile = bootloaderfile;
+ else
+ loadfile = tok;
+
+ ret = sb_load_file(cctx, loadfile);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Cannot load '%s'!\n",
+ cmd->lineno, tok);
+ goto err;
+ }
+ }
+
+ if (cctx->length & (SB_BLOCK_SIZE - 1)) {
+ fprintf(stderr, "#%i ERR: Unaligned payload!\n",
+ cmd->lineno);
+ }
+
+ /*
+ * Construct the command.
+ */
+ ccmd->header.checksum = 0x5a;
+ ccmd->header.tag = ROM_LOAD_CMD;
+ ccmd->header.flags = dcd;
+
+ ccmd->load.address = dest;
+ ccmd->load.count = cctx->length;
+ ccmd->load.crc32 = pbl_crc32(0,
+ (const char *)cctx->data,
+ cctx->length);
+
+ cctx->size = sizeof(*ccmd) + cctx->length;
+
+ /*
+ * Append the command to the last section.
+ */
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ return 0;
+
+err:
+ free(cctx);
+ return ret;
+}
+
+static int sb_build_command_fill(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd)
+{
+ struct sb_section_ctx *sctx = ictx->sect_tail;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ char *tok;
+ uint32_t address, pattern, length;
+ int ret;
+
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+
+ ccmd = &cctx->payload;
+
+ /*
+ * Prepare the command.
+ */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing FILL address!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Read fill destination address. */
+ ret = sb_token_to_long(tok, &address);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect FILL address!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ tok = strtok(NULL, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing FILL pattern!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Read fill pattern address. */
+ ret = sb_token_to_long(tok, &pattern);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect FILL pattern!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ tok = strtok(NULL, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing FILL length!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Read fill pattern address. */
+ ret = sb_token_to_long(tok, &length);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect FILL length!\n",
+ cmd->lineno);
+ goto err;
+ }
+
+ /*
+ * Construct the command.
+ */
+ ccmd->header.checksum = 0x5a;
+ ccmd->header.tag = ROM_FILL_CMD;
+
+ ccmd->fill.address = address;
+ ccmd->fill.count = length;
+ ccmd->fill.pattern = pattern;
+
+ cctx->size = sizeof(*ccmd);
+
+ /*
+ * Append the command to the last section.
+ */
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ return 0;
+
+err:
+ free(cctx);
+ return ret;
+}
+
+static int sb_build_command_jump_call(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd,
+ unsigned int is_call)
+{
+ struct sb_section_ctx *sctx = ictx->sect_tail;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ char *tok;
+ uint32_t dest, arg = 0x0;
+ uint32_t hab = 0;
+ int ret;
+ const char *cmdname = is_call ? "CALL" : "JUMP";
+
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+
+ ccmd = &cctx->payload;
+
+ /*
+ * Prepare the command.
+ */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr,
+ "#%i ERR: Missing %s address or 'HAB'!\n",
+ cmd->lineno, cmdname);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Check for "HAB" flag. */
+ if (!strcmp(tok, "HAB")) {
+ hab = is_call ? ROM_CALL_CMD_FLAG_HAB : ROM_JUMP_CMD_FLAG_HAB;
+ tok = strtok(NULL, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing %s address!\n",
+ cmd->lineno, cmdname);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+ /* Read load destination address. */
+ ret = sb_token_to_long(tok, &dest);
+ if (ret) {
+ fprintf(stderr, "#%i ERR: Incorrect %s address!\n",
+ cmd->lineno, cmdname);
+ goto err;
+ }
+
+ tok = strtok(NULL, " ");
+ if (tok) {
+ ret = sb_token_to_long(tok, &arg);
+ if (ret) {
+ fprintf(stderr,
+ "#%i ERR: Incorrect %s argument!\n",
+ cmd->lineno, cmdname);
+ goto err;
+ }
+ }
+
+ /*
+ * Construct the command.
+ */
+ ccmd->header.checksum = 0x5a;
+ ccmd->header.tag = is_call ? ROM_CALL_CMD : ROM_JUMP_CMD;
+ ccmd->header.flags = hab;
+
+ ccmd->call.address = dest;
+ ccmd->call.argument = arg;
+
+ cctx->size = sizeof(*ccmd);
+
+ /*
+ * Append the command to the last section.
+ */
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ return 0;
+
+err:
+ free(cctx);
+ return ret;
+}
+
+static int sb_build_command_jump(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd)
+{
+ return sb_build_command_jump_call(ictx, cmd, 0);
+}
+
+static int sb_build_command_call(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd)
+{
+ return sb_build_command_jump_call(ictx, cmd, 1);
+}
+
+static int sb_build_command_mode(struct sb_image_ctx *ictx,
+ struct sb_cmd_list *cmd)
+{
+ struct sb_section_ctx *sctx = ictx->sect_tail;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ char *tok;
+ int ret;
+ unsigned int i;
+ uint32_t mode = 0xffffffff;
+
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+
+ ccmd = &cctx->payload;
+
+ /*
+ * Prepare the command.
+ */
+ tok = strtok(cmd->cmd, " ");
+ if (!tok) {
+ fprintf(stderr, "#%i ERR: Missing MODE boot mode argument!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(modetable); i++) {
+ if (!strcmp(tok, modetable[i].name)) {
+ mode = modetable[i].mode;
+ break;
+ }
+
+ if (!modetable[i].altname)
+ continue;
+
+ if (!strcmp(tok, modetable[i].altname)) {
+ mode = modetable[i].mode;
+ break;
+ }
+ }
+
+ if (mode == 0xffffffff) {
+ fprintf(stderr, "#%i ERR: Invalid MODE boot mode argument!\n",
+ cmd->lineno);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Construct the command.
+ */
+ ccmd->header.checksum = 0x5a;
+ ccmd->header.tag = ROM_MODE_CMD;
+
+ ccmd->mode.mode = mode;
+
+ cctx->size = sizeof(*ccmd);
+
+ /*
+ * Append the command to the last section.
+ */
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ return 0;
+
+err:
+ free(cctx);
+ return ret;
+}
+
+static int sb_prefill_image_header(struct sb_image_ctx *ictx)
+{
+ struct sb_boot_image_header *hdr = &ictx->payload;
+
+ /* Fill signatures */
+ memcpy(hdr->signature1, "STMP", 4);
+ memcpy(hdr->signature2, "sgtl", 4);
+
+ /* SB Image version 1.1 */
+ hdr->major_version = SB_VERSION_MAJOR;
+ hdr->minor_version = SB_VERSION_MINOR;
+
+ /* Boot image major version */
+ hdr->product_version.major = htons(0x999);
+ hdr->product_version.minor = htons(0x999);
+ hdr->product_version.revision = htons(0x999);
+ /* Boot image major version */
+ hdr->component_version.major = htons(0x999);
+ hdr->component_version.minor = htons(0x999);
+ hdr->component_version.revision = htons(0x999);
+
+ /* Drive tag must be 0x0 for i.MX23 */
+ hdr->drive_tag = 0;
+
+ hdr->header_blocks =
+ sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
+ hdr->section_header_size =
+ sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
+ hdr->timestamp_us = sb_get_timestamp() * 1000000;
+
+ /* FIXME -- add proper config option */
+ hdr->flags = ictx->verbose_boot ? SB_IMAGE_FLAG_VERBOSE : 0,
+
+ /* FIXME -- We support only default key */
+ hdr->key_count = 1;
+
+ return 0;
+}
+
+static int sb_postfill_image_header(struct sb_image_ctx *ictx)
+{
+ struct sb_boot_image_header *hdr = &ictx->payload;
+ struct sb_section_ctx *sctx = ictx->sect_head;
+ uint32_t kd_size, sections_blocks;
+ EVP_MD_CTX md_ctx;
+
+ /* The main SB header size in blocks. */
+ hdr->image_blocks = hdr->header_blocks;
+
+ /* Size of the key dictionary, which has single zero entry. */
+ kd_size = hdr->key_count * sizeof(struct sb_key_dictionary_key);
+ hdr->image_blocks += kd_size / SB_BLOCK_SIZE;
+
+ /* Now count the payloads. */
+ hdr->section_count = ictx->sect_count;
+ while (sctx) {
+ hdr->image_blocks += sctx->size / SB_BLOCK_SIZE;
+ sctx = sctx->sect;
+ }
+
+ if (!ictx->sect_boot_found) {
+ fprintf(stderr, "ERR: No bootable section selected!\n");
+ return -EINVAL;
+ }
+ hdr->first_boot_section_id = ictx->sect_boot;
+
+ /* The n * SB section size in blocks. */
+ sections_blocks = hdr->section_count * hdr->section_header_size;
+ hdr->image_blocks += sections_blocks;
+
+ /* Key dictionary offset. */
+ hdr->key_dictionary_block = hdr->header_blocks + sections_blocks;
+
+ /* Digest of the whole image. */
+ hdr->image_blocks += 2;
+
+ /* Pointer past the dictionary. */
+ hdr->first_boot_tag_block =
+ hdr->key_dictionary_block + kd_size / SB_BLOCK_SIZE;
+
+ /* Compute header digest. */
+ EVP_MD_CTX_init(&md_ctx);
+
+ EVP_DigestInit(&md_ctx, EVP_sha1());
+ EVP_DigestUpdate(&md_ctx, hdr->signature1,
+ sizeof(struct sb_boot_image_header) -
+ sizeof(hdr->digest));
+ EVP_DigestFinal(&md_ctx, hdr->digest, NULL);
+
+ return 0;
+}
+
+static int sb_fixup_sections_and_tags(struct sb_image_ctx *ictx)
+{
+ /* Fixup the placement of sections. */
+ struct sb_boot_image_header *ihdr = &ictx->payload;
+ struct sb_section_ctx *sctx = ictx->sect_head;
+ struct sb_sections_header *shdr;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ uint32_t offset = ihdr->first_boot_tag_block;
+
+ while (sctx) {
+ shdr = &sctx->payload;
+
+ /* Fill in the section TAG offset. */
+ shdr->section_offset = offset + 1;
+ offset += shdr->section_size;
+
+ /* Section length is measured from the TAG block. */
+ shdr->section_size--;
+
+ /* Fixup the TAG command. */
+ cctx = sctx->cmd_head;
+ while (cctx) {
+ ccmd = &cctx->payload;
+ if (ccmd->header.tag == ROM_TAG_CMD) {
+ ccmd->tag.section_number = shdr->section_number;
+ ccmd->tag.section_length = shdr->section_size;
+ ccmd->tag.section_flags = shdr->section_flags;
+ }
+
+ /* Update the command checksum. */
+ ccmd->header.checksum = sb_command_checksum(ccmd);
+
+ cctx = cctx->cmd;
+ }
+
+ sctx = sctx->sect;
+ }
+
+ return 0;
+}
+
+static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
+{
+ char *tok;
+ char *line = cmd->cmd;
+ char *rptr = NULL;
+ int ret;
+
+ /* Analyze the identifier on this line first. */
+ tok = strtok_r(line, " ", &rptr);
+ if (!tok || (strlen(tok) == 0)) {
+ fprintf(stderr, "#%i ERR: Invalid line!\n", cmd->lineno);
+ return -EINVAL;
+ }
+
+ cmd->cmd = rptr;
+
+ /* DCD */
+ if (!strcmp(tok, "DCD")) {
+ ictx->in_section = 0;
+ ictx->in_dcd = 1;
+ sb_build_dcd(ictx, cmd);
+ return 0;
+ }
+
+ /* Section */
+ if (!strcmp(tok, "SECTION")) {
+ ictx->in_section = 1;
+ ictx->in_dcd = 0;
+ sb_build_section(ictx, cmd);
+ return 0;
+ }
+
+ if (!ictx->in_section && !ictx->in_dcd) {
+ fprintf(stderr, "#%i ERR: Data outside of a section!\n",
+ cmd->lineno);
+ return -EINVAL;
+ }
+
+ if (ictx->in_section) {
+ /* Section commands */
+ if (!strcmp(tok, "NOP")) {
+ ret = sb_build_command_nop(ictx);
+ } else if (!strcmp(tok, "TAG")) {
+ ret = sb_build_command_tag(ictx, cmd);
+ } else if (!strcmp(tok, "LOAD")) {
+ ret = sb_build_command_load(ictx, cmd);
+ } else if (!strcmp(tok, "FILL")) {
+ ret = sb_build_command_fill(ictx, cmd);
+ } else if (!strcmp(tok, "JUMP")) {
+ ret = sb_build_command_jump(ictx, cmd);
+ } else if (!strcmp(tok, "CALL")) {
+ ret = sb_build_command_call(ictx, cmd);
+ } else if (!strcmp(tok, "MODE")) {
+ ret = sb_build_command_mode(ictx, cmd);
+ } else {
+ fprintf(stderr,
+ "#%i ERR: Unsupported instruction '%s'!\n",
+ cmd->lineno, tok);
+ return -ENOTSUP;
+ }
+ } else if (ictx->in_dcd) {
+ char *lptr;
+ uint32_t ilen = '1';
+
+ tok = strtok_r(tok, ".", &lptr);
+ if (!tok || (strlen(tok) == 0) || (lptr && strlen(lptr) != 1)) {
+ fprintf(stderr, "#%i ERR: Invalid line!\n",
+ cmd->lineno);
+ return -EINVAL;
+ }
+
+ if (lptr &&
+ (lptr[0] != '1' && lptr[0] != '2' && lptr[0] != '4')) {
+ fprintf(stderr, "#%i ERR: Invalid instruction width!\n",
+ cmd->lineno);
+ return -EINVAL;
+ }
+
+ if (lptr)
+ ilen = lptr[0] - '1';
+
+ /* DCD commands */
+ if (!strcmp(tok, "WRITE")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_WRITE | ilen);
+ } else if (!strcmp(tok, "ANDC")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_ANDC | ilen);
+ } else if (!strcmp(tok, "ORR")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_ORR | ilen);
+ } else if (!strcmp(tok, "EQZ")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_CHK_EQZ | ilen);
+ } else if (!strcmp(tok, "EQ")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_CHK_EQ | ilen);
+ } else if (!strcmp(tok, "NEQ")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_CHK_NEQ | ilen);
+ } else if (!strcmp(tok, "NEZ")) {
+ ret = sb_build_dcd_block(ictx, cmd,
+ SB_DCD_CHK_NEZ | ilen);
+ } else if (!strcmp(tok, "NOOP")) {
+ ret = sb_build_dcd_block(ictx, cmd, SB_DCD_NOOP);
+ } else {
+ fprintf(stderr,
+ "#%i ERR: Unsupported instruction '%s'!\n",
+ cmd->lineno, tok);
+ return -ENOTSUP;
+ }
+ } else {
+ fprintf(stderr, "#%i ERR: Unsupported instruction '%s'!\n",
+ cmd->lineno, tok);
+ return -ENOTSUP;
+ }
+
+ /*
+ * Here we have at least one section with one command, otherwise we
+ * would have failed already higher above.
+ *
+ * FIXME -- should the updating happen here ?
+ */
+ if (ictx->in_section && !ret) {
+ ictx->sect_tail->size += ictx->sect_tail->cmd_tail->size;
+ ictx->sect_tail->payload.section_size =
+ ictx->sect_tail->size / SB_BLOCK_SIZE;
+ }
+
+ return ret;
+}
+
+static int sb_load_cmdfile(struct sb_image_ctx *ictx)
+{
+ struct sb_cmd_list cmd;
+ int lineno = 1, ret;
+ FILE *fp;
+ char *line = NULL;
+ ssize_t rlen;
+ size_t len;
+
+ fp = fopen(ictx->cfg_filename, "r");
+ if (!fp)
+ goto err_file;
+
+ while ((rlen = getline(&line, &len, fp)) > 0) {
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* Strip the trailing newline. */
+ line[rlen - 1] = '\0';
+
+ cmd.cmd = line;
+ cmd.len = rlen;
+ cmd.lineno = lineno++;
+
+ ret = sb_parse_line(ictx, &cmd);
+ if (ret)
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(line);
+
+ fclose(fp);
+
+ return ret;
+
+err_file:
+ fprintf(stderr, "ERR: Failed to load file \"%s\"\n",
+ ictx->cfg_filename);
+ return -EINVAL;
+}
+
+static int sb_build_tree_from_cfg(struct sb_image_ctx *ictx)
+{
+ int ret;
+
+ ret = sb_load_cmdfile(ictx);
+ if (ret)
+ return ret;
+
+ ret = sb_prefill_image_header(ictx);
+ if (ret)
+ return ret;
+
+ ret = sb_postfill_image_header(ictx);
+ if (ret)
+ return ret;
+
+ ret = sb_fixup_sections_and_tags(ictx);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sb_verify_image_header(struct sb_image_ctx *ictx,
+ FILE *fp, long fsize)
+{
+ /* Verify static fields in the image header. */
+ struct sb_boot_image_header *hdr = &ictx->payload;
+ const char *stat[2] = { "[PASS]", "[FAIL]" };
+ struct tm tm;
+ int sz, ret = 0;
+ unsigned char digest[20];
+ EVP_MD_CTX md_ctx;
+ unsigned long size;
+
+ /* Start image-wide crypto. */
+ EVP_MD_CTX_init(&ictx->md_ctx);
+ EVP_DigestInit(&ictx->md_ctx, EVP_sha1());
+
+ soprintf(ictx, "---------- Verifying SB Image Header ----------\n");
+
+ size = fread(&ictx->payload, 1, sizeof(ictx->payload), fp);
+ if (size != sizeof(ictx->payload)) {
+ fprintf(stderr, "ERR: SB image header too short!\n");
+ return -EINVAL;
+ }
+
+ /* Compute header digest. */
+ EVP_MD_CTX_init(&md_ctx);
+ EVP_DigestInit(&md_ctx, EVP_sha1());
+ EVP_DigestUpdate(&md_ctx, hdr->signature1,
+ sizeof(struct sb_boot_image_header) -
+ sizeof(hdr->digest));
+ EVP_DigestFinal(&md_ctx, digest, NULL);
+
+ sb_aes_init(ictx, NULL, 1);
+ sb_encrypt_sb_header(ictx);
+
+ if (memcmp(digest, hdr->digest, 20))
+ ret = -EINVAL;
+ soprintf(ictx, "%s Image header checksum: %s\n", stat[!!ret],
+ ret ? "BAD" : "OK");
+ if (ret)
+ return ret;
+
+ if (memcmp(hdr->signature1, "STMP", 4) ||
+ memcmp(hdr->signature2, "sgtl", 4))
+ ret = -EINVAL;
+ soprintf(ictx, "%s Signatures: '%.4s' '%.4s'\n",
+ stat[!!ret], hdr->signature1, hdr->signature2);
+ if (ret)
+ return ret;
+
+ if ((hdr->major_version != SB_VERSION_MAJOR) ||
+ ((hdr->minor_version != 1) && (hdr->minor_version != 2)))
+ ret = -EINVAL;
+ soprintf(ictx, "%s Image version: v%i.%i\n", stat[!!ret],
+ hdr->major_version, hdr->minor_version);
+ if (ret)
+ return ret;
+
+ ret = sb_get_time(hdr->timestamp_us / 1000000, &tm);
+ soprintf(ictx,
+ "%s Creation time: %02i:%02i:%02i %02i/%02i/%04i\n",
+ stat[!!ret], tm.tm_hour, tm.tm_min, tm.tm_sec,
+ tm.tm_mday, tm.tm_mon, tm.tm_year + 2000);
+ if (ret)
+ return ret;
+
+ soprintf(ictx, "%s Product version: %x.%x.%x\n", stat[0],
+ ntohs(hdr->product_version.major),
+ ntohs(hdr->product_version.minor),
+ ntohs(hdr->product_version.revision));
+ soprintf(ictx, "%s Component version: %x.%x.%x\n", stat[0],
+ ntohs(hdr->component_version.major),
+ ntohs(hdr->component_version.minor),
+ ntohs(hdr->component_version.revision));
+
+ if (hdr->flags & ~SB_IMAGE_FLAG_VERBOSE)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Image flags: %s\n", stat[!!ret],
+ hdr->flags & SB_IMAGE_FLAG_VERBOSE ? "Verbose_boot" : "");
+ if (ret)
+ return ret;
+
+ if (hdr->drive_tag != 0)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Drive tag: %i\n", stat[!!ret],
+ hdr->drive_tag);
+ if (ret)
+ return ret;
+
+ sz = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
+ if (hdr->header_blocks != sz)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Image header size (blocks): %i\n", stat[!!ret],
+ hdr->header_blocks);
+ if (ret)
+ return ret;
+
+ sz = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
+ if (hdr->section_header_size != sz)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Section header size (blocks): %i\n", stat[!!ret],
+ hdr->section_header_size);
+ if (ret)
+ return ret;
+
+ soprintf(ictx, "%s Sections count: %i\n", stat[!!ret],
+ hdr->section_count);
+ soprintf(ictx, "%s First bootable section %i\n", stat[!!ret],
+ hdr->first_boot_section_id);
+
+ if (hdr->image_blocks != fsize / SB_BLOCK_SIZE)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Image size (blocks): %i\n", stat[!!ret],
+ hdr->image_blocks);
+ if (ret)
+ return ret;
+
+ sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count;
+ if (hdr->key_dictionary_block != sz)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Key dict offset (blocks): %i\n", stat[!!ret],
+ hdr->key_dictionary_block);
+ if (ret)
+ return ret;
+
+ if (hdr->key_count != 1)
+ ret = -EINVAL;
+ soprintf(ictx, "%s Number of encryption keys: %i\n", stat[!!ret],
+ hdr->key_count);
+ if (ret)
+ return ret;
+
+ sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count;
+ sz += hdr->key_count *
+ sizeof(struct sb_key_dictionary_key) / SB_BLOCK_SIZE;
+ if (hdr->first_boot_tag_block != (unsigned)sz)
+ ret = -EINVAL;
+ soprintf(ictx, "%s First TAG block (blocks): %i\n", stat[!!ret],
+ hdr->first_boot_tag_block);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void sb_decrypt_tag(struct sb_image_ctx *ictx,
+ struct sb_cmd_ctx *cctx)
+{
+ EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+ struct sb_command *cmd = &cctx->payload;
+
+ sb_aes_crypt(ictx, (uint8_t *)&cctx->c_payload,
+ (uint8_t *)&cctx->payload, sizeof(*cmd));
+ EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd));
+}
+
+static int sb_verify_command(struct sb_image_ctx *ictx,
+ struct sb_cmd_ctx *cctx, FILE *fp,
+ unsigned long *tsize)
+{
+ struct sb_command *ccmd = &cctx->payload;
+ unsigned long size, asize;
+ char *csum, *flag = "";
+ int ret;
+ unsigned int i;
+ uint8_t csn, csc = ccmd->header.checksum;
+ ccmd->header.checksum = 0x5a;
+ csn = sb_command_checksum(ccmd);
+ ccmd->header.checksum = csc;
+
+ if (csc == csn)
+ ret = 0;
+ else
+ ret = -EINVAL;
+ csum = ret ? "checksum BAD" : "checksum OK";
+
+ switch (ccmd->header.tag) {
+ case ROM_NOP_CMD:
+ soprintf(ictx, " NOOP # %s\n", csum);
+ return ret;
+ case ROM_TAG_CMD:
+ if (ccmd->header.flags & ROM_TAG_CMD_FLAG_ROM_LAST_TAG)
+ flag = "LAST";
+ soprintf(ictx, " TAG %s # %s\n", flag, csum);
+ sb_aes_reinit(ictx, 0);
+ return ret;
+ case ROM_LOAD_CMD:
+ soprintf(ictx, " LOAD addr=0x%08x length=0x%08x # %s\n",
+ ccmd->load.address, ccmd->load.count, csum);
+
+ cctx->length = ccmd->load.count;
+ asize = roundup(cctx->length, SB_BLOCK_SIZE);
+ cctx->data = malloc(asize);
+ if (!cctx->data)
+ return -ENOMEM;
+
+ size = fread(cctx->data, 1, asize, fp);
+ if (size != asize) {
+ fprintf(stderr,
+ "ERR: SB LOAD command payload too short!\n");
+ return -EINVAL;
+ }
+
+ *tsize += size;
+
+ EVP_DigestUpdate(&ictx->md_ctx, cctx->data, asize);
+ sb_aes_crypt(ictx, cctx->data, cctx->data, asize);
+
+ if (ccmd->load.crc32 != pbl_crc32(0,
+ (const char *)cctx->data,
+ asize)) {
+ fprintf(stderr,
+ "ERR: SB LOAD command payload CRC32 invalid!\n");
+ return -EINVAL;
+ }
+ return 0;
+ case ROM_FILL_CMD:
+ soprintf(ictx,
+ " FILL addr=0x%08x length=0x%08x pattern=0x%08x # %s\n",
+ ccmd->fill.address, ccmd->fill.count,
+ ccmd->fill.pattern, csum);
+ return 0;
+ case ROM_JUMP_CMD:
+ if (ccmd->header.flags & ROM_JUMP_CMD_FLAG_HAB)
+ flag = " HAB";
+ soprintf(ictx,
+ " JUMP%s addr=0x%08x r0_arg=0x%08x # %s\n",
+ flag, ccmd->fill.address, ccmd->jump.argument, csum);
+ return 0;
+ case ROM_CALL_CMD:
+ if (ccmd->header.flags & ROM_CALL_CMD_FLAG_HAB)
+ flag = " HAB";
+ soprintf(ictx,
+ " CALL%s addr=0x%08x r0_arg=0x%08x # %s\n",
+ flag, ccmd->fill.address, ccmd->jump.argument, csum);
+ return 0;
+ case ROM_MODE_CMD:
+ for (i = 0; i < ARRAY_SIZE(modetable); i++) {
+ if (ccmd->mode.mode == modetable[i].mode) {
+ soprintf(ictx, " MODE %s # %s\n",
+ modetable[i].name, csum);
+ break;
+ }
+ }
+ fprintf(stderr, " MODE !INVALID! # %s\n", csum);
+ return 0;
+ }
+
+ return ret;
+}
+
+static int sb_verify_commands(struct sb_image_ctx *ictx,
+ struct sb_section_ctx *sctx, FILE *fp)
+{
+ unsigned long size, tsize = 0;
+ struct sb_cmd_ctx *cctx;
+ int ret;
+
+ sb_aes_reinit(ictx, 0);
+
+ while (tsize < sctx->size) {
+ cctx = calloc(1, sizeof(*cctx));
+ if (!cctx)
+ return -ENOMEM;
+ if (!sctx->cmd_head) {
+ sctx->cmd_head = cctx;
+ sctx->cmd_tail = cctx;
+ } else {
+ sctx->cmd_tail->cmd = cctx;
+ sctx->cmd_tail = cctx;
+ }
+
+ size = fread(&cctx->c_payload, 1, sizeof(cctx->c_payload), fp);
+ if (size != sizeof(cctx->c_payload)) {
+ fprintf(stderr, "ERR: SB command header too short!\n");
+ return -EINVAL;
+ }
+
+ tsize += size;
+
+ sb_decrypt_tag(ictx, cctx);
+
+ ret = sb_verify_command(ictx, cctx, fp, &tsize);
+ if (ret)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sb_verify_sections_cmds(struct sb_image_ctx *ictx, FILE *fp)
+{
+ struct sb_boot_image_header *hdr = &ictx->payload;
+ struct sb_sections_header *shdr;
+ unsigned int i;
+ int ret;
+ struct sb_section_ctx *sctx;
+ unsigned long size;
+ char *bootable = "";
+
+ soprintf(ictx, "----- Verifying SB Sections and Commands -----\n");
+
+ for (i = 0; i < hdr->section_count; i++) {
+ sctx = calloc(1, sizeof(*sctx));
+ if (!sctx)
+ return -ENOMEM;
+ if (!ictx->sect_head) {
+ ictx->sect_head = sctx;
+ ictx->sect_tail = sctx;
+ } else {
+ ictx->sect_tail->sect = sctx;
+ ictx->sect_tail = sctx;
+ }
+
+ size = fread(&sctx->payload, 1, sizeof(sctx->payload), fp);
+ if (size != sizeof(sctx->payload)) {
+ fprintf(stderr, "ERR: SB section header too short!\n");
+ return -EINVAL;
+ }
+ }
+
+ size = fread(&ictx->sb_dict_key, 1, sizeof(ictx->sb_dict_key), fp);
+ if (size != sizeof(ictx->sb_dict_key)) {
+ fprintf(stderr, "ERR: SB key dictionary too short!\n");
+ return -EINVAL;
+ }
+
+ sb_encrypt_sb_sections_header(ictx);
+ sb_aes_reinit(ictx, 0);
+ sb_decrypt_key_dictionary_key(ictx);
+
+ sb_aes_reinit(ictx, 0);
+
+ sctx = ictx->sect_head;
+ while (sctx) {
+ shdr = &sctx->payload;
+
+ if (shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) {
+ sctx->boot = 1;
+ bootable = " BOOTABLE";
+ }
+
+ sctx->size = (shdr->section_size * SB_BLOCK_SIZE) +
+ sizeof(struct sb_command);
+ soprintf(ictx, "SECTION 0x%x%s # size = %i bytes\n",
+ shdr->section_number, bootable, sctx->size);
+
+ if (shdr->section_flags & ~SB_SECTION_FLAG_BOOTABLE)
+ fprintf(stderr, " WARN: Unknown section flag(s) %08x\n",
+ shdr->section_flags);
+
+ if ((shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) &&
+ (hdr->first_boot_section_id != shdr->section_number)) {
+ fprintf(stderr,
+ " WARN: Bootable section does ID not match image header ID!\n");
+ }
+
+ ret = sb_verify_commands(ictx, sctx, fp);
+ if (ret)
+ return ret;
+
+ sctx = sctx->sect;
+ }
+
+ /*
+ * FIXME IDEA:
+ * check if the first TAG command is at sctx->section_offset
+ */
+ return 0;
+}
+
+static int sb_verify_image_end(struct sb_image_ctx *ictx,
+ FILE *fp, off_t filesz)
+{
+ uint8_t digest[32];
+ unsigned long size;
+ off_t pos;
+ int ret;
+
+ soprintf(ictx, "------------- Verifying image end -------------\n");
+
+ size = fread(digest, 1, sizeof(digest), fp);
+ if (size != sizeof(digest)) {
+ fprintf(stderr, "ERR: SB key dictionary too short!\n");
+ return -EINVAL;
+ }
+
+ pos = ftell(fp);
+ if (pos != filesz) {
+ fprintf(stderr, "ERR: Trailing data past the image!\n");
+ return -EINVAL;
+ }
+
+ /* Check the image digest. */
+ EVP_DigestFinal(&ictx->md_ctx, ictx->digest, NULL);
+
+ /* Decrypt the image digest from the input image. */
+ sb_aes_reinit(ictx, 0);
+ sb_aes_crypt(ictx, digest, digest, sizeof(digest));
+
+ /* Check all of 20 bytes of the SHA1 hash. */
+ ret = memcmp(digest, ictx->digest, 20) ? -EINVAL : 0;
+
+ if (ret)
+ soprintf(ictx, "[FAIL] Full-image checksum: BAD\n");
+ else
+ soprintf(ictx, "[PASS] Full-image checksum: OK\n");
+
+ return ret;
+}
+
+
+static int sb_build_tree_from_img(struct sb_image_ctx *ictx)
+{
+ long filesize;
+ int ret;
+ FILE *fp;
+
+ if (!ictx->input_filename) {
+ fprintf(stderr, "ERR: Missing filename!\n");
+ return -EINVAL;
+ }
+
+ fp = fopen(ictx->input_filename, "r");
+ if (!fp)
+ goto err_open;
+
+ ret = fseek(fp, 0, SEEK_END);
+ if (ret < 0)
+ goto err_file;
+
+ filesize = ftell(fp);
+ if (filesize < 0)
+ goto err_file;
+
+ ret = fseek(fp, 0, SEEK_SET);
+ if (ret < 0)
+ goto err_file;
+
+ if (filesize < (signed)sizeof(ictx->payload)) {
+ fprintf(stderr, "ERR: File too short!\n");
+ goto err_file;
+ }
+
+ /* Load and verify image header */
+ ret = sb_verify_image_header(ictx, fp, filesize);
+ if (ret)
+ goto err_verify;
+
+ /* Load and verify sections and commands */
+ ret = sb_verify_sections_cmds(ictx, fp);
+ if (ret)
+ goto err_verify;
+
+ ret = sb_verify_image_end(ictx, fp, filesize);
+ if (ret)
+ goto err_verify;
+
+ ret = 0;
+
+err_verify:
+ soprintf(ictx, "-------------------- Result -------------------\n");
+ soprintf(ictx, "Verification %s\n", ret ? "FAILED" : "PASSED");
+
+ /* Stop the encryption session. */
+ sb_aes_deinit(&ictx->cipher_ctx);
+
+ fclose(fp);
+ return ret;
+
+err_file:
+ fclose(fp);
+err_open:
+ fprintf(stderr, "ERR: Failed to load file \"%s\"\n",
+ ictx->input_filename);
+ return -EINVAL;
+}
+
+static void sb_free_image(struct sb_image_ctx *ictx)
+{
+ struct sb_section_ctx *sctx = ictx->sect_head, *s_head;
+ struct sb_dcd_ctx *dctx = ictx->dcd_head, *d_head;
+ struct sb_cmd_ctx *cctx, *c_head;
+
+ while (sctx) {
+ s_head = sctx;
+ c_head = sctx->cmd_head;
+
+ while (c_head) {
+ cctx = c_head;
+ c_head = c_head->cmd;
+ if (cctx->data)
+ free(cctx->data);
+ free(cctx);
+ }
+
+ sctx = sctx->sect;
+ free(s_head);
+ }
+
+ while (dctx) {
+ d_head = dctx;
+ dctx = dctx->dcd;
+ free(d_head->payload);
+ free(d_head);
+ }
+}
+
+static int mxsimage_verify_print_header(char *file, int silent)
+{
+ int ret;
+ struct sb_image_ctx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ ctx.input_filename = file;
+ ctx.silent_dump = silent;
+
+ ret = sb_build_tree_from_img(&ctx);
+ sb_free_image(&ctx);
+
+ return ret;
+}
+
+static int sb_build_image(struct sb_image_ctx *ictx)
+{
+ struct sb_boot_image_header *sb_header = &ictx->payload;
+ struct sb_section_ctx *sctx;
+ struct sb_cmd_ctx *cctx;
+ struct sb_command *ccmd;
+ struct sb_key_dictionary_key *sb_dict_key = &ictx->sb_dict_key;
+ int fd;
+ ssize_t now;
+
+ uint8_t *image, *iptr;
+
+ /* Calculate image size. */
+ uint32_t size = sizeof(*sb_header) +
+ ictx->sect_count * sizeof(struct sb_sections_header) +
+ sizeof(*sb_dict_key) + sizeof(ictx->digest);
+
+ sctx = ictx->sect_head;
+ while (sctx) {
+ size += sctx->size;
+ sctx = sctx->sect;
+ };
+
+ image = malloc(size);
+ if (!image)
+ return -ENOMEM;
+ iptr = image;
+
+ memcpy(iptr, sb_header, sizeof(*sb_header));
+ iptr += sizeof(*sb_header);
+
+ sctx = ictx->sect_head;
+ while (sctx) {
+ memcpy(iptr, &sctx->payload, sizeof(struct sb_sections_header));
+ iptr += sizeof(struct sb_sections_header);
+ sctx = sctx->sect;
+ };
+
+ memcpy(iptr, sb_dict_key, sizeof(*sb_dict_key));
+ iptr += sizeof(*sb_dict_key);
+
+ sctx = ictx->sect_head;
+ while (sctx) {
+ cctx = sctx->cmd_head;
+ while (cctx) {
+ ccmd = &cctx->payload;
+
+ memcpy(iptr, &cctx->c_payload, sizeof(cctx->payload));
+ iptr += sizeof(cctx->payload);
+
+ if (ccmd->header.tag == ROM_LOAD_CMD) {
+ memcpy(iptr, cctx->data, cctx->length);
+ iptr += cctx->length;
+ }
+
+ cctx = cctx->cmd;
+ }
+
+ sctx = sctx->sect;
+ };
+
+ memcpy(iptr, ictx->digest, sizeof(ictx->digest));
+ iptr += sizeof(ictx->digest);
+
+ fd = open(ictx->output_filename, O_WRONLY | O_CREAT, 0644);
+ if (fd < 0)
+ return -errno;
+
+ while (size) {
+ now = write(fd, image, size);
+ if (now < 0)
+ return -errno;
+ image += now;
+ size -= now;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+static int mxsimage_generate(const char *configfile, const char *imagefile)
+{
+ int ret;
+ struct sb_image_ctx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ ctx.cfg_filename = configfile;
+ ctx.output_filename = imagefile;
+ ctx.verbose_boot = 1;
+
+ ret = sb_build_tree_from_cfg(&ctx);
+ if (ret)
+ goto fail;
+
+ ret = sb_encrypt_image(&ctx);
+ if (!ret)
+ ret = sb_build_image(&ctx);
+
+fail:
+ sb_free_image(&ctx);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ int opt;
+ char *configfile = NULL, *outfile = NULL, *verify = NULL;
+
+ while ((opt = getopt(argc, argv, "p:b:c:o:v:")) != -1) {
+ switch (opt) {
+ case 'p':
+ prepfile = optarg;
+ break;
+ case 'b':
+ bootloaderfile = optarg;
+ break;
+ case 'c':
+ configfile = optarg;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'v':
+ verify = optarg;
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ if (verify) {
+ ret = mxsimage_verify_print_header(verify, 0);
+ if (ret)
+ exit(1);
+ else
+ exit(0);
+ }
+
+ if (!configfile) {
+ fprintf(stderr, "Configfile missing\n");
+ exit(1);
+ }
+
+ if (!outfile) {
+ fprintf(stderr, "outfile missing\n");
+ exit(1);
+ }
+
+ ret = mxsimage_generate(configfile, outfile);
+ if (ret)
+ exit(1);
+
+ return 0;
+}