* MXS initialization support
@ 2014-12-09 19:03 Sascha Hauer
2014-12-09 19:03 ` [PATCH 01/13] scripts: add mxsimage tool Sascha Hauer
` (13 more replies)
0 siblings, 14 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
The following adds initialization support for Freescale MXS SoCs.
With this the imfamous Freescale Bootlets can finally be replaced.
The initialization code is based on the corresponding U-Boot code,
thank you Marek for making this possible.
Sascha
----------------------------------------------------------------
Sascha Hauer (13):
scripts: add mxsimage tool
scripts: Add mxsboot tool
scripts: Add mxs-usb-loader tool
drivers: remove unnecessary mach/imx-regs.h include
ARM: MXS: remove unnecessary mach/imx-regs.h include
ARM: Add U-Boot specific io functions
ARM: mxs: Add lowlevel setup from U-Boot
ARM: Add get_sp() and get_lr() functions
ARM: MXS: Add more base address defines
ARM: MXS: Enable iomux support for pbl
ARM: MXS: Add multiimage support
ARM: MXS: Update Karo TX28 board support
Documentation: Add documentation for booting Freescale MXS SoCs
Documentation/boards/mxs.rst | 119 +
Documentation/boards/mxs/KaRo-TX28.rst | 19 +-
arch/arm/boards/karo-tx28/env/config | 41 -
arch/arm/boards/karo-tx28/lowlevel.c | 58 +-
arch/arm/configs/tx28stk5_defconfig | 84 +-
arch/arm/include/asm/common.h | 26 +
arch/arm/include/asm/io.h | 57 +
arch/arm/mach-mxs/Kconfig | 9 +
arch/arm/mach-mxs/Makefile | 2 +
arch/arm/mach-mxs/clocksource-imx23.c | 2 +-
arch/arm/mach-mxs/clocksource-imx28.c | 2 +-
arch/arm/mach-mxs/include/mach/imx23-regs.h | 3 +
arch/arm/mach-mxs/include/mach/imx28-regs.h | 3 +
arch/arm/mach-mxs/include/mach/init.h | 30 +
arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h | 208 ++
arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h | 283 +++
arch/arm/mach-mxs/include/mach/regs-common.h | 69 +
arch/arm/mach-mxs/include/mach/regs-lradc.h | 387 +++
arch/arm/mach-mxs/include/mach/regs-power-mx28.h | 408 ++++
arch/arm/mach-mxs/include/mach/regs-rtc.h | 134 +
arch/arm/mach-mxs/lradc-init.c | 70 +
arch/arm/mach-mxs/mem-init.c | 292 +++
arch/arm/mach-mxs/ocotp.c | 1 -
arch/arm/mach-mxs/power-init.c | 1274 ++++++++++
arch/arm/mach-mxs/soc-imx23.c | 2 +-
arch/arm/mach-mxs/soc-imx28.c | 2 +-
arch/arm/mach-mxs/usb-imx23.c | 2 +-
arch/arm/mach-mxs/usb-imx28.c | 2 +-
drivers/clk/mxs/clk-imx23.c | 2 +-
drivers/clk/mxs/clk-imx28.c | 2 +-
drivers/mci/mxs.c | 1 -
drivers/serial/serial_auart.c | 1 -
drivers/serial/stm-serial.c | 1 -
drivers/spi/mxs_spi.c | 1 -
drivers/video/stm.c | 1 -
images/.gitignore | 2 +
images/Makefile | 3 +-
images/Makefile.mxs | 38 +
scripts/.gitignore | 1 +
scripts/Makefile | 5 +
scripts/mxs-usb-loader.c | 236 ++
scripts/mxsimage.c | 2561 ++++++++++++++++++++
42 files changed, 6346 insertions(+), 98 deletions(-)
create mode 100644 Documentation/boards/mxs.rst
delete mode 100644 arch/arm/boards/karo-tx28/env/config
create mode 100644 arch/arm/mach-mxs/include/mach/init.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-common.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-lradc.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-power-mx28.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-rtc.h
create mode 100644 arch/arm/mach-mxs/lradc-init.c
create mode 100644 arch/arm/mach-mxs/mem-init.c
create mode 100644 arch/arm/mach-mxs/power-init.c
create mode 100644 images/Makefile.mxs
create mode 100644 scripts/mxs-usb-loader.c
create mode 100644 scripts/mxsimage.c
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 01/13] scripts: add mxsimage tool
2014-12-09 19:03 MXS initialization support Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 02/13] scripts: Add mxsboot tool Sascha Hauer
` (12 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
This is copied from U-Boot v2014.10 and modified for use with
barebox:
- Add a main() function to make it a standalone tool
- Add option to pass in the prepare stage and bootloader
image as options. If the config file contains @PREP@ or
@BOOTLOADER@ the string will be replaced with the actual
image file passed via the -p and -b options.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
scripts/.gitignore | 1 +
scripts/Makefile | 2 +
scripts/mxsimage.c | 2561 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 2564 insertions(+)
create mode 100644 scripts/mxsimage.c
diff --git a/scripts/.gitignore b/scripts/.gitignore
index b574b22..153b7d7 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -22,3 +22,4 @@ bareboximd-target
bareboxstate
bareboxstate-target
mk-am35xx-spi-image
+mxsimage
diff --git a/scripts/Makefile b/scripts/Makefile
index 5483a64..f97fd0c 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -19,6 +19,8 @@ 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
+HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl`
subdir-y += mod
subdir-$(CONFIG_OMAP4_USBBOOT) += omap4_usbboot
diff --git a/scripts/mxsimage.c b/scripts/mxsimage.c
new file mode 100644
index 0000000..0a5f6a0
--- /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;
+}
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 02/13] scripts: Add mxsboot tool
2014-12-09 19:03 MXS initialization support Sascha Hauer
2014-12-09 19:03 ` [PATCH 01/13] scripts: add mxsimage tool Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-10 7:01 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 03/13] scripts: Add mxs-usb-loader tool Sascha Hauer
` (11 subsequent siblings)
13 siblings, 1 reply; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
Copied from U-Boot v2014.10 and changed to use getopt instead
of handcrafted parsing.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/boards/karo-tx28/env/config | 41 ------------------------------------
scripts/Makefile | 2 +-
2 files changed, 1 insertion(+), 42 deletions(-)
delete mode 100644 arch/arm/boards/karo-tx28/env/config
diff --git a/arch/arm/boards/karo-tx28/env/config b/arch/arm/boards/karo-tx28/env/config
deleted file mode 100644
index a6b1025..0000000
--- 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/scripts/Makefile b/scripts/Makefile
index f97fd0c..442eba5 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -19,7 +19,7 @@ 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
+hostprogs-$(CONFIG_ARCH_MXS) += mxsimage mxsboot
HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl`
subdir-y += mod
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 03/13] scripts: Add mxs-usb-loader tool
2014-12-09 19:03 MXS initialization support Sascha Hauer
2014-12-09 19:03 ` [PATCH 01/13] scripts: add mxsimage tool Sascha Hauer
2014-12-09 19:03 ` [PATCH 02/13] scripts: Add mxsboot tool Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 04/13] drivers: remove unnecessary mach/imx-regs.h include Sascha Hauer
` (10 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
This is directly taken from the rockbox projects sbloader tool,
just renamed to mxs-usb-loader to avoid confusion with bareboxes
several different image tools.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-mxs/Kconfig | 7 ++
scripts/Makefile | 3 +
scripts/mxs-usb-loader.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 246 insertions(+)
create mode 100644 scripts/mxs-usb-loader.c
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 214f940..997e326 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -134,4 +134,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/scripts/Makefile b/scripts/Makefile
index 442eba5..74c2213 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -21,6 +21,9 @@ 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 0000000..8529274
--- /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;
+}
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 04/13] drivers: remove unnecessary mach/imx-regs.h include
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (2 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 03/13] scripts: Add mxs-usb-loader tool Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 05/13] ARM: MXS: " Sascha Hauer
` (9 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
And replace the ones needed with the SoC specific header.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/clk/mxs/clk-imx23.c | 2 +-
drivers/clk/mxs/clk-imx28.c | 2 +-
drivers/mci/mxs.c | 1 -
drivers/serial/serial_auart.c | 1 -
drivers/serial/stm-serial.c | 1 -
drivers/spi/mxs_spi.c | 1 -
drivers/video/stm.c | 1 -
7 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 1f84e9f..8bf27c1 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 aa2924c..77a13bc 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 d6565ca..367964c 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 ae6c5b8..87b2e33 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 39ff7ae..e5f57dc 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 9a35e09..8932103 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 175e4b6..3c90c0d 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
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 05/13] ARM: MXS: remove unnecessary mach/imx-regs.h include
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (3 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 04/13] drivers: remove unnecessary mach/imx-regs.h include Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 06/13] ARM: Add U-Boot specific io functions Sascha Hauer
` (8 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
And replace the ones needed with the SoC specific header.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-mxs/clocksource-imx23.c | 2 +-
arch/arm/mach-mxs/clocksource-imx28.c | 2 +-
arch/arm/mach-mxs/ocotp.c | 1 -
arch/arm/mach-mxs/soc-imx23.c | 2 +-
arch/arm/mach-mxs/soc-imx28.c | 2 +-
arch/arm/mach-mxs/usb-imx23.c | 2 +-
arch/arm/mach-mxs/usb-imx28.c | 2 +-
7 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-mxs/clocksource-imx23.c b/arch/arm/mach-mxs/clocksource-imx23.c
index d9b7c1a..8279ee2 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 d26aa93..4f38af6 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/ocotp.c b/arch/arm/mach-mxs/ocotp.c
index c7c24e0..abdd445 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/soc-imx23.c b/arch/arm/mach-mxs/soc-imx23.c
index 825ea20..b219865 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 01bc20a..c7252f5 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 8bed11d..e626396 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 1c982a0..a87d4f6 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
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 06/13] ARM: Add U-Boot specific io functions
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (4 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 05/13] ARM: MXS: " Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 07/13] ARM: mxs: Add lowlevel setup from U-Boot Sascha Hauer
` (7 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
To make it easier to adopt code from U-Boot.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/include/asm/io.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index ccf1f59..850a99c 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 */
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 07/13] ARM: mxs: Add lowlevel setup from U-Boot
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (5 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 06/13] ARM: Add U-Boot specific io functions Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 08/13] ARM: Add get_sp() and get_lr() functions Sascha Hauer
` (6 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
U-Boot has code to replace the infamous Freescale bootlet code.
This patch adds this for barebox with some changes:
- Separate it more into mx23/mx28 functions instead of mxs functions
with #ifdefs for the actual SoC
- Add mx2x_power_init_battery_input() power entry point for boards
which have a regulated input on the battery pin to supply the board.
- Export more functions to be more flexible when boards need non standard
setup.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-mxs/Makefile | 1 +
arch/arm/mach-mxs/include/mach/init.h | 30 +
arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h | 208 ++++
arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h | 283 +++++
arch/arm/mach-mxs/include/mach/regs-common.h | 69 ++
arch/arm/mach-mxs/include/mach/regs-lradc.h | 387 ++++++
arch/arm/mach-mxs/include/mach/regs-power-mx28.h | 408 +++++++
arch/arm/mach-mxs/include/mach/regs-rtc.h | 134 ++
arch/arm/mach-mxs/lradc-init.c | 70 ++
arch/arm/mach-mxs/mem-init.c | 292 +++++
arch/arm/mach-mxs/power-init.c | 1274 ++++++++++++++++++++
11 files changed, 3156 insertions(+)
create mode 100644 arch/arm/mach-mxs/include/mach/init.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-clkctrl-mx28.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-common.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-lradc.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-power-mx28.h
create mode 100644 arch/arm/mach-mxs/include/mach/regs-rtc.h
create mode 100644 arch/arm/mach-mxs/lradc-init.c
create mode 100644 arch/arm/mach-mxs/mem-init.c
create mode 100644 arch/arm/mach-mxs/power-init.c
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index bd6892e..bf949bc 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -3,3 +3,4 @@ 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/include/mach/init.h b/arch/arm/mach-mxs/include/mach/init.h
new file mode 100644
index 0000000..d1ac2e4
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/init.h
@@ -0,0 +1,30 @@
+/*
+ * 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);
+
+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/regs-clkctrl-mx23.h b/arch/arm/mach-mxs/include/mach/regs-clkctrl-mx23.h
new file mode 100644
index 0000000..289b159
--- /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 0000000..aebb489
--- /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 0000000..e54a220
--- /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 0000000..7f624be
--- /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 0000000..7b73496
--- /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 0000000..bd8fdad
--- /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 0000000..682a475
--- /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, ®s->hw_lradc_ctrl0_clr);
+ writel(LRADC_CTRL0_CLKGATE, ®s->hw_lradc_ctrl0_clr);
+ writel(LRADC_CTRL0_ONCHIP_GROUNDREF, ®s->hw_lradc_ctrl0_clr);
+
+ clrsetbits_le32(®s->hw_lradc_ctrl3,
+ LRADC_CTRL3_CYCLE_TIME_MASK,
+ LRADC_CTRL3_CYCLE_TIME_6MHZ);
+
+ clrsetbits_le32(®s->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(®s->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT))
+ return;
+
+ writel(LRADC_CTRL1_LRADC7_IRQ_EN, ®s->hw_lradc_ctrl1_clr);
+ writel(LRADC_CTRL1_LRADC7_IRQ, ®s->hw_lradc_ctrl1_clr);
+
+ clrsetbits_le32(®s->hw_lradc_conversion,
+ LRADC_CONVERSION_SCALE_FACTOR_MASK,
+ LRADC_CONVERSION_SCALE_FACTOR_LI_ION);
+ writel(LRADC_CONVERSION_AUTOMATIC, ®s->hw_lradc_conversion_set);
+
+ /* Configure the channel. */
+ writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
+ ®s->hw_lradc_ctrl2_clr);
+ writel(0xffffffff, ®s->hw_lradc_ch7_clr);
+ clrbits_le32(®s->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK);
+ writel(LRADC_CH_ACCUMULATE, ®s->hw_lradc_ch7_clr);
+
+ /* Schedule the channel. */
+ writel(1 << 7, ®s->hw_lradc_ctrl0_set);
+
+ /* Start the channel sampling. */
+ writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) |
+ ((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) |
+ 100, ®s->hw_lradc_delay3);
+
+ writel(0xffffffff, ®s->hw_lradc_ch7_clr);
+
+ writel(LRADC_DELAY_KICK, ®s->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 0000000..f4328b7
--- /dev/null
+++ b/arch/arm/mach-mxs/mem-init.c
@@ -0,0 +1,292 @@
+/*
+ * Freescale i.MX28 RAM 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 <linux/compiler.h>
+#include <stmp-device.h>
+
+#include <mach/init.h>
+#include <mach/regs-power-mx28.h>
+#include <mach/regs-clkctrl-mx28.h>
+
+static 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
+ */
+static 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;
+
+ clrbits_le32(&power_regs->hw_power_vddmemctrl,
+ POWER_VDDMEMCTRL_ENABLE_ILIMIT);
+
+}
+
+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.
+ */
+ stmp_reset_block((struct mxs_register_32 *)IMX_EMI_BASE, 0);
+
+ 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);
+ mxs_early_delay(20000);
+
+ /* 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/power-init.c b/arch/arm/mach-mxs/power-init.c
new file mode 100644
index 0000000..b4431c4
--- /dev/null
+++ b/arch/arm/mach-mxs/power-init.c
@@ -0,0 +1,1274 @@
+/*
+ * 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_vddd_cfg, 1350, 1200);
+ 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);
+ mxs_power_set_vddx(&mxs_vddd_cfg, 1350, 1200);
+
+ 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))
+ ;
+}
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 08/13] ARM: Add get_sp() and get_lr() functions
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (6 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 07/13] ARM: mxs: Add lowlevel setup from U-Boot Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 09/13] ARM: MXS: Add more base address defines Sascha Hauer
` (5 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
In case it's needed for some early code.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/include/asm/common.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/arm/include/asm/common.h b/arch/arm/include/asm/common.h
index 133bb8e..9ff3b19 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));
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 09/13] ARM: MXS: Add more base address defines
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (7 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 08/13] ARM: Add get_sp() and get_lr() functions Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 10/13] ARM: MXS: Enable iomux support for pbl Sascha Hauer
` (4 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-mxs/include/mach/imx23-regs.h | 3 +++
arch/arm/mach-mxs/include/mach/imx28-regs.h | 3 +++
2 files changed, 6 insertions(+)
diff --git a/arch/arm/mach-mxs/include/mach/imx23-regs.h b/arch/arm/mach-mxs/include/mach/imx23-regs.h
index 7fb664b..3fd2f3d 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 0882829..de0d882 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
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 10/13] ARM: MXS: Enable iomux support for pbl
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (8 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 09/13] ARM: MXS: Add more base address defines Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 11/13] ARM: MXS: Add multiimage support Sascha Hauer
` (3 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
Upcoming lowlevel code for MXS needs the iomux setup functions
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-mxs/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index bf949bc..e384336 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -1,4 +1,5 @@
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
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 11/13] ARM: MXS: Add multiimage support
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (9 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 10/13] ARM: MXS: Enable iomux support for pbl Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 12/13] ARM: MXS: Update Karo TX28 board support Sascha Hauer
` (2 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
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.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
images/.gitignore | 2 ++
images/Makefile | 3 ++-
images/Makefile.mxs | 22 ++++++++++++++++++++++
3 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 images/Makefile.mxs
diff --git a/images/.gitignore b/images/.gitignore
index d27e71a..c5377d9 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 c55cbdc..7c3aaf7 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 0000000..c6056e6
--- /dev/null
+++ b/images/Makefile.mxs
@@ -0,0 +1,22 @@
+#
+# 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
+mxscfg = $(srctree)/arch/arm/mach-mxs/mxsimg.cfg
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 12/13] ARM: MXS: Update Karo TX28 board support
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (10 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 11/13] ARM: MXS: Add multiimage support Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 13/13] Documentation: Add documentation for booting Freescale MXS SoCs Sascha Hauer
2014-12-10 12:28 ` MXS initialization support Marek Vasut
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
- enable multiimage support to generate bootstream, sd-card and 2nd
stage images
- Enable new defaultenv support
- Enable more features
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Documentation/boards/mxs/KaRo-TX28.rst | 19 ++------
arch/arm/boards/karo-tx28/lowlevel.c | 58 ++++++++++++++++++++++-
arch/arm/configs/tx28stk5_defconfig | 84 ++++++++++++++++++++++++----------
arch/arm/mach-mxs/Kconfig | 2 +
images/Makefile.mxs | 16 +++++++
5 files changed, 137 insertions(+), 42 deletions(-)
diff --git a/Documentation/boards/mxs/KaRo-TX28.rst b/Documentation/boards/mxs/KaRo-TX28.rst
index 0fbd4df..0c5dc71 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/karo-tx28/lowlevel.c b/arch/arm/boards/karo-tx28/lowlevel.c
index aa3b09b..f747f3f 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 <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/tx28stk5_defconfig b/arch/arm/configs/tx28stk5_defconfig
index fe80d98..d5714f2 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/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 997e326..6ef055e 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -59,6 +59,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.
diff --git a/images/Makefile.mxs b/images/Makefile.mxs
index c6056e6..a21fa08 100644
--- a/images/Makefile.mxs
+++ b/images/Makefile.mxs
@@ -20,3 +20,19 @@ $(obj)/%.mxssd: $(obj)/%
board = $(srctree)/arch/$(ARCH)/boards
mxscfg = $(srctree)/arch/arm/mach-mxs/mxsimg.cfg
+
+pblx-$(CONFIG_MACH_BOSCH_SCM) += start_barebox_bosch_scm prep_start_barebox_bosch_scm
+PREP_start_barebox_bosch_scm.pblx.mxsbs = start_barebox_bosch_scm_prep
+CFG_start_barebox_bosch_scm.mxsbs = $(mxscfg)
+FILE_barebox-bosch-scm.img = start_barebox_bosch_scm.mxsbs
+image-$(CONFIG_MACH_BOSCH_SCM) += barebox-bosch-scm.img
+
+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 = $(mxscfg)
+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
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 13/13] Documentation: Add documentation for booting Freescale MXS SoCs
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (11 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 12/13] ARM: MXS: Update Karo TX28 board support Sascha Hauer
@ 2014-12-09 19:03 ` Sascha Hauer
2014-12-10 12:28 ` MXS initialization support Marek Vasut
13 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-09 19:03 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Documentation/boards/mxs.rst | 119 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 Documentation/boards/mxs.rst
diff --git a/Documentation/boards/mxs.rst b/Documentation/boards/mxs.rst
new file mode 100644
index 0000000..6c8bdb5
--- /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.
--
2.1.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 02/13] scripts: Add mxsboot tool
2014-12-09 19:03 ` [PATCH 02/13] scripts: Add mxsboot tool Sascha Hauer
@ 2014-12-10 7:01 ` Sascha Hauer
0 siblings, 0 replies; 16+ messages in thread
From: Sascha Hauer @ 2014-12-10 7:01 UTC (permalink / raw)
To: barebox; +Cc: Marek Vasut
On Tue, Dec 09, 2014 at 08:03:25PM +0100, Sascha Hauer wrote:
> Copied from U-Boot v2014.10 and changed to use getopt instead
> of handcrafted parsing.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> arch/arm/boards/karo-tx28/env/config | 41 ------------------------------------
> scripts/Makefile | 2 +-
> 2 files changed, 1 insertion(+), 42 deletions(-)
> delete mode 100644 arch/arm/boards/karo-tx28/env/config
>
> diff --git a/arch/arm/boards/karo-tx28/env/config b/arch/arm/boards/karo-tx28/env/config
This shouldn't be here but in the Karo patch.
Instead the mxsboot tool should be in this patch:
------------------------------8<----------------------------
From 06f17c1eb78b63ce5175feb2962d5ebbfcee406a Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Tue, 9 Dec 2014 17:07:16 +0100
Subject: [PATCH] scripts: Add mxsboot tool
Copied from U-Boot v2014.10 and changed to use getopt instead
of handcrafted parsing.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
scripts/.gitignore | 1 +
scripts/Makefile | 2 +-
scripts/mxsboot.c | 641 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 643 insertions(+), 1 deletion(-)
create mode 100644 scripts/mxsboot.c
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 153b7d7..6203589 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -23,3 +23,4 @@ bareboxstate
bareboxstate-target
mk-am35xx-spi-image
mxsimage
+mxsboot
diff --git a/scripts/Makefile b/scripts/Makefile
index f97fd0c..442eba5 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -19,7 +19,7 @@ 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
+hostprogs-$(CONFIG_ARCH_MXS) += mxsimage mxsboot
HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl`
subdir-y += mod
diff --git a/scripts/mxsboot.c b/scripts/mxsboot.c
new file mode 100644
index 0000000..2b90b25
--- /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;
+}
--
2.1.3
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: MXS initialization support
2014-12-09 19:03 MXS initialization support Sascha Hauer
` (12 preceding siblings ...)
2014-12-09 19:03 ` [PATCH 13/13] Documentation: Add documentation for booting Freescale MXS SoCs Sascha Hauer
@ 2014-12-10 12:28 ` Marek Vasut
13 siblings, 0 replies; 16+ messages in thread
From: Marek Vasut @ 2014-12-10 12:28 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
On Tuesday, December 09, 2014 at 08:03:23 PM, Sascha Hauer wrote:
> The following adds initialization support for Freescale MXS SoCs.
> With this the imfamous Freescale Bootlets can finally be replaced.
> The initialization code is based on the corresponding U-Boot code,
> thank you Marek for making this possible.
Woohoo, another slab of code in barebox :)
Would you by any chance be able to synchronise bugfixes between the two (uboot
and barebox) codebases please ? That'd be really helpful.
Thanks!
Best regards,
Marek Vasut
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2014-12-10 14:34 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-09 19:03 MXS initialization support Sascha Hauer
2014-12-09 19:03 ` [PATCH 01/13] scripts: add mxsimage tool Sascha Hauer
2014-12-09 19:03 ` [PATCH 02/13] scripts: Add mxsboot tool Sascha Hauer
2014-12-10 7:01 ` Sascha Hauer
2014-12-09 19:03 ` [PATCH 03/13] scripts: Add mxs-usb-loader tool Sascha Hauer
2014-12-09 19:03 ` [PATCH 04/13] drivers: remove unnecessary mach/imx-regs.h include Sascha Hauer
2014-12-09 19:03 ` [PATCH 05/13] ARM: MXS: " Sascha Hauer
2014-12-09 19:03 ` [PATCH 06/13] ARM: Add U-Boot specific io functions Sascha Hauer
2014-12-09 19:03 ` [PATCH 07/13] ARM: mxs: Add lowlevel setup from U-Boot Sascha Hauer
2014-12-09 19:03 ` [PATCH 08/13] ARM: Add get_sp() and get_lr() functions Sascha Hauer
2014-12-09 19:03 ` [PATCH 09/13] ARM: MXS: Add more base address defines Sascha Hauer
2014-12-09 19:03 ` [PATCH 10/13] ARM: MXS: Enable iomux support for pbl Sascha Hauer
2014-12-09 19:03 ` [PATCH 11/13] ARM: MXS: Add multiimage support Sascha Hauer
2014-12-09 19:03 ` [PATCH 12/13] ARM: MXS: Update Karo TX28 board support Sascha Hauer
2014-12-09 19:03 ` [PATCH 13/13] Documentation: Add documentation for booting Freescale MXS SoCs Sascha Hauer
2014-12-10 12:28 ` MXS initialization support Marek Vasut
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox