Patchwork [U-Boot,14/31] iMX28: Add MMC SPL

login
register
mail settings
Submitter Marek Vasut
Date Sept. 8, 2011, 8:42 p.m.
Message ID <1315514579-19215-15-git-send-email-marek.vasut@gmail.com>
Download mbox | patch
Permalink /patch/113969/
State Changes Requested
Headers show

Comments

Marek Vasut - Sept. 8, 2011, 8:42 p.m.
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Andy Fleming <afleming@gmail.com>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Detlev Zundel <dzu@denx.de>
---
 mmc_spl/board/denx/m28evk/Makefile     |  102 ++++
 mmc_spl/board/denx/m28evk/m28_init.h   |   36 ++
 mmc_spl/board/denx/m28evk/mem_init.c   |  218 ++++++++
 mmc_spl/board/denx/m28evk/mmc_boot.c   |  271 ++++++++++
 mmc_spl/board/denx/m28evk/power_init.c |  915 ++++++++++++++++++++++++++++++++
 mmc_spl/board/denx/m28evk/start.S      |  402 ++++++++++++++
 mmc_spl/board/denx/m28evk/u-boot.bd    |   14 +
 mmc_spl/board/denx/m28evk/u-boot.lds   |   87 +++
 8 files changed, 2045 insertions(+), 0 deletions(-)
 create mode 100644 mmc_spl/board/denx/m28evk/Makefile
 create mode 100644 mmc_spl/board/denx/m28evk/m28_init.h
 create mode 100644 mmc_spl/board/denx/m28evk/mem_init.c
 create mode 100644 mmc_spl/board/denx/m28evk/mmc_boot.c
 create mode 100644 mmc_spl/board/denx/m28evk/power_init.c
 create mode 100644 mmc_spl/board/denx/m28evk/start.S
 create mode 100644 mmc_spl/board/denx/m28evk/u-boot.bd
 create mode 100644 mmc_spl/board/denx/m28evk/u-boot.lds
Chander Kashyap - Sept. 9, 2011, 5:44 a.m.
Dear Marek Vasut,
Please use newly added spl framework to add mmc spl support.

On 9 September 2011 02:12, Marek Vasut <marek.vasut@gmail.com> wrote:
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Andy Fleming <afleming@gmail.com>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Wolfgang Denk <wd@denx.de>
> Cc: Detlev Zundel <dzu@denx.de>
> ---
>  mmc_spl/board/denx/m28evk/Makefile     |  102 ++++
>  mmc_spl/board/denx/m28evk/m28_init.h   |   36 ++
>  mmc_spl/board/denx/m28evk/mem_init.c   |  218 ++++++++
>  mmc_spl/board/denx/m28evk/mmc_boot.c   |  271 ++++++++++
>  mmc_spl/board/denx/m28evk/power_init.c |  915 ++++++++++++++++++++++++++++++++
>  mmc_spl/board/denx/m28evk/start.S      |  402 ++++++++++++++
>  mmc_spl/board/denx/m28evk/u-boot.bd    |   14 +
>  mmc_spl/board/denx/m28evk/u-boot.lds   |   87 +++
>  8 files changed, 2045 insertions(+), 0 deletions(-)
>  create mode 100644 mmc_spl/board/denx/m28evk/Makefile
>  create mode 100644 mmc_spl/board/denx/m28evk/m28_init.h
>  create mode 100644 mmc_spl/board/denx/m28evk/mem_init.c
>  create mode 100644 mmc_spl/board/denx/m28evk/mmc_boot.c
>  create mode 100644 mmc_spl/board/denx/m28evk/power_init.c
>  create mode 100644 mmc_spl/board/denx/m28evk/start.S
>  create mode 100644 mmc_spl/board/denx/m28evk/u-boot.bd
>  create mode 100644 mmc_spl/board/denx/m28evk/u-boot.lds
>
> diff --git a/mmc_spl/board/denx/m28evk/Makefile b/mmc_spl/board/denx/m28evk/Makefile
> new file mode 100644
> index 0000000..c08eac9
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/Makefile
> @@ -0,0 +1,102 @@
> +#
> +# (C) Copyright 2006-2007
> +# Stefan Roese, DENX Software Engineering, sr@denx.de.
> +#
> +# (C) Copyright 2008
> +# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
> +#
> +# (C) Copyright 2011
> +# Chander Kashyap, Samsung Electronics, <k.chander@samsung.com>
> +#
> +# See file CREDITS for list of people who contributed to this
> +# project.
> +#
> +# 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 program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> +# MA 02111-1307 USA
> +#
> +
> +CONFIG_MMC_SPL = y
> +
> +include $(TOPDIR)/config.mk
> +
> +LDSCRIPT= $(TOPDIR)/mmc_spl/board/$(BOARDDIR)/u-boot.lds
> +LDFLAGS        = -Bstatic -T $(mmcobj)u-boot.lds -Ttext 0x0 $(PLATFORM_LDFLAGS)
> +AFLAGS += -DCONFIG_MMC_SPL
> +AFLAGS += -DCONFIG_SPL_BUILD
> +CFLAGS += -DCONFIG_MMC_SPL
> +CFLAGS += -DCONFIG_SPL_BUILD
> +
> +SOBJS  = start.o _udivsi3.o _divsi3.o
> +COBJS  = mmc_boot.o iomux.o power_init.o mem_init.o div0.o
> +
> +SRCS   := $($(SOBJS:.o=.S) $(COBJS:.o=.c))
> +OBJS   := $(addprefix $(obj),$(SOBJS) $(COBJS))
> +__OBJS := $(SOBJS) $(COBJS)
> +LNDIR  := $(OBJTREE)/mmc_spl/board/$(BOARDDIR)
> +
> +mmcobj := $(OBJTREE)/mmc_spl/
> +
> +
> +ALL = $(mmcobj)u-boot-spl $(mmcobj)u-boot-spl.bin  $(mmcobj)u-boot-mmc-spl.bin
> +
> +all:    $(obj).depend $(ALL)
> +
> +$(mmcobj)u-boot-mmc-spl.bin:   $(mmcobj)u-boot-spl.bin
> +       cp $< $@
> +
> +$(mmcobj)u-boot-spl.bin:       $(mmcobj)u-boot-spl
> +       $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
> +
> +$(mmcobj)u-boot-spl:   $(OBJS) $(mmcobj)u-boot.lds
> +       cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) \
> +               -Map $(mmcobj)u-boot-spl.map \
> +               -o $(mmcobj)u-boot-spl
> +
> +$(mmcobj)u-boot.lds: $(LDSCRIPT)
> +       $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
> +
> +# create symbolic links for common files
> +
> +# from cpu directory
> +iomux.c:
> +       @rm -f $@
> +       @ln -s $(TOPDIR)/arch/arm/cpu/arm926ejs/mx28/iomux.c $@
> +
> +_udivsi3.S:
> +       @rm -f $@
> +       @ln -s $(TOPDIR)/arch/arm/lib/_udivsi3.S $@
> +
> +_divsi3.S:
> +       @rm -f $@
> +       @ln -s $(TOPDIR)/arch/arm/lib/_divsi3.S $@
> +
> +div0.c:
> +       @rm -f $@
> +       @ln -s $(TOPDIR)/arch/arm/lib/div0.c $@
> +
> +#########################################################################
> +
> +$(obj)%.o:     %.S
> +       $(CC) $(AFLAGS) -c -o $@ $<
> +
> +$(obj)%.o:     %.c
> +       $(CC) $(CFLAGS) -c -o $@ $<
> +
> +# defines $(obj).depend target
> +include $(SRCTREE)/rules.mk
> +
> +sinclude $(obj).depend
> +
> +#########################################################################
> diff --git a/mmc_spl/board/denx/m28evk/m28_init.h b/mmc_spl/board/denx/m28evk/m28_init.h
> new file mode 100644
> index 0000000..7f569e0
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/m28_init.h
> @@ -0,0 +1,36 @@
> +/*
> + * Freescale i.MX28 SPL functions
> + *
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + * on behalf of DENX Software Engineering GmbH
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef        __M28_INIT_H__
> +#define        __M28_INIT_H__
> +
> +void early_delay(int delay);
> +
> +void mx28_power_init(void);
> +void mx28_power_wait_pswitch(void);
> +
> +void mx28_mem_init(void);
> +
> +#endif /* __M28_INIT_H__ */
> diff --git a/mmc_spl/board/denx/m28evk/mem_init.c b/mmc_spl/board/denx/m28evk/mem_init.c
> new file mode 100644
> index 0000000..4cd6fba
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/mem_init.c
> @@ -0,0 +1,218 @@
> +/*
> + * Freescale i.MX28 RAM init
> + *
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + * on behalf of DENX Software Engineering GmbH
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <config.h>
> +#include <asm/io.h>
> +#include <asm/arch/iomux-mx28.h>
> +#include <asm/arch/regs-common.h>
> +#include <asm/arch/regs-base.h>
> +#include <asm/arch/regs-clkctrl.h>
> +#include <asm/arch/regs-pinctrl.h>
> +#include <asm/arch/regs-rtc.h>
> +#include <asm/arch/regs-power.h>
> +
> +#include "m28_init.h"
> +
> +uint32_t dram_vals[] = {
> +       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, 0x05060302, 0x06005003, 0x0a0000c8,
> +       0x02009c40, 0x0000030c, 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, 0xf5014b27, 0xf5014b27, 0xf5014b27, 0xf5014b27,
> +       0x07000300, 0x07000300, 0x07000300, 0x07000300, 0x00000006,
> +       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, 0x00020304, 0x00000004,
> +       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
> +       0x00000000, 0x01010000, 0x01000000, 0x03030000, 0x00010303,
> +       0x01020202, 0x00000000, 0x02040303, 0x21002103, 0x00061200,
> +       0x06120612, 0x04320432, 0x04320432, 0x00040004, 0x00040004,
> +       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010001
> +};
> +
> +void init_m28_200mhz_ddr2(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(dram_vals); i++)
> +               writel(dram_vals[i], MXS_DRAM_BASE + (4 * i));
> +}
> +
> +void mx28_mem_init_clock(void)
> +{
> +       struct mx28_clkctrl_regs *clkctrl_regs =
> +               (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
> +
> +       /* Gate EMI clock */
> +       writel(CLKCTRL_FRAC0_CLKGATEEMI,
> +               &clkctrl_regs->hw_clkctrl_frac0_set);
> +
> +       /* EMI = 205MHz */
> +       writel(CLKCTRL_FRAC0_EMIFRAC_MASK,
> +               &clkctrl_regs->hw_clkctrl_frac0_set);
> +       writel((0x2a << CLKCTRL_FRAC0_EMIFRAC_OFFSET) &
> +               CLKCTRL_FRAC0_EMIFRAC_MASK,
> +               &clkctrl_regs->hw_clkctrl_frac0_clr);
> +
> +       /* Ungate EMI clock */
> +       writel(CLKCTRL_FRAC0_CLKGATEEMI,
> +               &clkctrl_regs->hw_clkctrl_frac0_clr);
> +
> +       early_delay(11000);
> +
> +       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);
> +
> +       early_delay(10000);
> +}
> +
> +void mx28_mem_setup_cpu_and_hbus(void)
> +{
> +       struct mx28_clkctrl_regs *clkctrl_regs =
> +               (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
> +
> +       /* CPU = 454MHz and ungate CPU clock */
> +       clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0,
> +               CLKCTRL_FRAC0_CPUFRAC_MASK | CLKCTRL_FRAC0_CLKGATECPU,
> +               19 << CLKCTRL_FRAC0_CPUFRAC_OFFSET);
> +
> +       /* 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);
> +
> +       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);
> +}
> +
> +void mx28_mem_setup_vdda(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +void mx28_mem_setup_vddd(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +
> +       writel((0x1c << POWER_VDDDCTRL_TRG_OFFSET) |
> +               (0x7 << POWER_VDDDCTRL_BO_OFFSET_OFFSET) |
> +               POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW,
> +               &power_regs->hw_power_vdddctrl);
> +}
> +
> +void mx28_mem_init(void)
> +{
> +       struct mx28_clkctrl_regs *clkctrl_regs =
> +               (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
> +       struct mx28_pinctrl_regs *pinctrl_regs =
> +               (struct mx28_pinctrl_regs *)MXS_PINCTRL_BASE;
> +
> +       /* Set DDR2 mode */
> +       writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2,
> +               &pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set);
> +
> +       /* Power up PLL0 */
> +       writel(CLKCTRL_PLL0CTRL0_POWER,
> +               &clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
> +
> +       early_delay(11000);
> +
> +       mx28_mem_init_clock();
> +
> +       mx28_mem_setup_vdda();
> +
> +       /*
> +        * Configure the DRAM registers
> +        */
> +
> +       /* Clear START bit from DRAM_CTL16 */
> +       clrbits_le32(MXS_DRAM_BASE + 0x40, 1);
> +
> +       init_m28_200mhz_ddr2();
> +
> +       /* Clear SREFRESH bit from DRAM_CTL17 */
> +       clrbits_le32(MXS_DRAM_BASE + 0x44, 1);
> +
> +       /* Set START bit in DRAM_CTL16 */
> +       setbits_le32(MXS_DRAM_BASE + 0x40, 1);
> +
> +       /* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */
> +       while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20)))
> +               ;
> +
> +       mx28_mem_setup_vddd();
> +
> +       early_delay(10000);
> +
> +       mx28_mem_setup_cpu_and_hbus();
> +}
> diff --git a/mmc_spl/board/denx/m28evk/mmc_boot.c b/mmc_spl/board/denx/m28evk/mmc_boot.c
> new file mode 100644
> index 0000000..4e670ea
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/mmc_boot.c
> @@ -0,0 +1,271 @@
> +/*
> + * Freescale i.MX28 Boot setup
> + *
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + * on behalf of DENX Software Engineering GmbH
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <config.h>
> +#include <asm/io.h>
> +#include <asm/arch/iomux-mx28.h>
> +
> +#include "m28_init.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.
> + */
> +#define        HW_DIGCTRL_MICROSECONDS 0x8001c0c0
> +void early_delay(int delay)
> +{
> +       uint32_t st = readl(HW_DIGCTRL_MICROSECONDS);
> +       st += delay;
> +       while (st > readl(HW_DIGCTRL_MICROSECONDS))
> +               ;
> +}
> +
> +#define        MUX_CONFIG_LED  (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
> +#define        MUX_CONFIG_LCD  (MXS_PAD_3V3 | MXS_PAD_4MA)
> +#define        MUX_CONFIG_TSC  (MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP)
> +#define        MUX_CONFIG_SSP0 (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_PULLUP)
> +#define        MUX_CONFIG_SSP2 (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP)
> +#define        MUX_CONFIG_GPMI (MXS_PAD_1V8 | MXS_PAD_4MA | MXS_PAD_NOPULL)
> +#define        MUX_CONFIG_ENET (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP)
> +#define        MUX_CONFIG_EMI  (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL)
> +
> +const iomux_cfg_t iomux_setup[] = {
> +       /* LED */
> +       MX28_PAD_ENET0_RXD3__GPIO_4_10 | MUX_CONFIG_LED,
> +
> +       /* framebuffer */
> +       MX28_PAD_LCD_D00__LCD_D0 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D01__LCD_D1 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D02__LCD_D2 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D03__LCD_D3 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D04__LCD_D4 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D05__LCD_D5 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D06__LCD_D6 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D07__LCD_D7 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D08__LCD_D8 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D09__LCD_D9 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D10__LCD_D10 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D11__LCD_D11 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D12__LCD_D12 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D13__LCD_D13 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D14__LCD_D14 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D15__LCD_D15 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D16__LCD_D16 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D17__LCD_D17 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D18__LCD_D18 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D19__LCD_D19 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D20__LCD_D20 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D21__LCD_D21 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D22__LCD_D22 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_D23__LCD_D23 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_RD_E__LCD_VSYNC | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_WR_RWN__LCD_HSYNC | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_RS__LCD_DOTCLK | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_CS__LCD_CS | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_VSYNC__LCD_VSYNC | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_HSYNC__LCD_HSYNC | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_DOTCLK__LCD_DOTCLK | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_ENABLE__GPIO_1_31 | MUX_CONFIG_LCD,
> +       MX28_PAD_LCD_RESET__GPIO_3_30 | MUX_CONFIG_LCD,
> +       MX28_PAD_PWM0__PWM_0 | MUX_CONFIG_LCD,
> +
> +       /* UART1 */
> +       MX28_PAD_AUART0_CTS__DUART_RX,
> +       MX28_PAD_AUART0_RTS__DUART_TX,
> +       MX28_PAD_AUART0_TX__DUART_RTS,
> +       MX28_PAD_AUART0_RX__DUART_CTS,
> +
> +       /* UART2 */
> +       MX28_PAD_AUART1_RX__AUART1_RX,
> +       MX28_PAD_AUART1_TX__AUART1_TX,
> +       MX28_PAD_AUART1_RTS__AUART1_RTS,
> +       MX28_PAD_AUART1_CTS__AUART1_CTS,
> +
> +       /* CAN */
> +       MX28_PAD_GPMI_RDY2__CAN0_TX,
> +       MX28_PAD_GPMI_RDY3__CAN0_RX,
> +
> +       /* I2C */
> +       MX28_PAD_I2C0_SCL__I2C0_SCL,
> +       MX28_PAD_I2C0_SDA__I2C0_SDA,
> +
> +       /* TSC2007 */
> +       MX28_PAD_SAIF0_MCLK__GPIO_3_20 | MUX_CONFIG_TSC,
> +
> +       /* MMC0 */
> +       MX28_PAD_SSP0_DATA0__SSP0_D0 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA1__SSP0_D1 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA2__SSP0_D2 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA3__SSP0_D3 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA4__SSP0_D4 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA5__SSP0_D5 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA6__SSP0_D6 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DATA7__SSP0_D7 | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_CMD__SSP0_CMD | MUX_CONFIG_SSP0,
> +       MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT |
> +               (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL),
> +       MX28_PAD_SSP0_SCK__SSP0_SCK |
> +               (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL),
> +       MX28_PAD_PWM3__GPIO_3_28 | MUX_CONFIG_SSP0,     /* Power .. FIXME */
> +       MX28_PAD_AUART2_CTS__GPIO_3_10, /* WP ... FIXME */
> +
> +       /* GPMI NAND */
> +       MX28_PAD_GPMI_D00__GPMI_D0 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D01__GPMI_D1 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D02__GPMI_D2 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D03__GPMI_D3 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D04__GPMI_D4 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D05__GPMI_D5 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D06__GPMI_D6 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_D07__GPMI_D7 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_CE0N__GPMI_CE0N | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_RDY0__GPMI_READY0 | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_RDN__GPMI_RDN |
> +               (MXS_PAD_1V8 | MXS_PAD_8MA | MXS_PAD_PULLUP),
> +       MX28_PAD_GPMI_WRN__GPMI_WRN | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_ALE__GPMI_ALE | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_CLE__GPMI_CLE | MUX_CONFIG_GPMI,
> +       MX28_PAD_GPMI_RESETN__GPMI_RESETN | MUX_CONFIG_GPMI,
> +
> +       /* FEC Ethernet */
> +       MX28_PAD_ENET0_MDC__ENET0_MDC | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_MDIO__ENET0_MDIO | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET_CLK__CLKCTRL_ENET | MUX_CONFIG_ENET,
> +
> +       MX28_PAD_ENET0_COL__ENET1_TX_EN | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_CRS__ENET1_RX_EN | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_RXD2__ENET1_RXD0 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_RXD3__ENET1_RXD1 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_TXD2__ENET1_TXD0 | MUX_CONFIG_ENET,
> +       MX28_PAD_ENET0_TXD3__ENET1_TXD1 | MUX_CONFIG_ENET,
> +
> +       /* I2C */
> +       MX28_PAD_I2C0_SCL__I2C0_SCL,
> +       MX28_PAD_I2C0_SDA__I2C0_SDA,
> +
> +       /* EMI */
> +       MX28_PAD_EMI_D00__EMI_DATA0 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D01__EMI_DATA1 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D02__EMI_DATA2 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D03__EMI_DATA3 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D04__EMI_DATA4 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D05__EMI_DATA5 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D06__EMI_DATA6 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D07__EMI_DATA7 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D08__EMI_DATA8 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D09__EMI_DATA9 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D10__EMI_DATA10 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D11__EMI_DATA11 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D12__EMI_DATA12 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D13__EMI_DATA13 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D14__EMI_DATA14 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_D15__EMI_DATA15 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_ODT0__EMI_ODT0 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_DQM0__EMI_DQM0 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_ODT1__EMI_ODT1 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_DQM1__EMI_DQM1 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_DDR_OPEN_FB__EMI_DDR_OPEN_FEEDBACK | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_CLK__EMI_CLK | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_DQS0__EMI_DQS0 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_DQS1__EMI_DQS1 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_DDR_OPEN__EMI_DDR_OPEN | MUX_CONFIG_EMI,
> +
> +       MX28_PAD_EMI_A00__EMI_ADDR0 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A01__EMI_ADDR1 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A02__EMI_ADDR2 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A03__EMI_ADDR3 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A04__EMI_ADDR4 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A05__EMI_ADDR5 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A06__EMI_ADDR6 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A07__EMI_ADDR7 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A08__EMI_ADDR8 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A09__EMI_ADDR9 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A10__EMI_ADDR10 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A11__EMI_ADDR11 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A12__EMI_ADDR12 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A13__EMI_ADDR13 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_A14__EMI_ADDR14 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_BA0__EMI_BA0 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_BA1__EMI_BA1 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_BA2__EMI_BA2 | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_CASN__EMI_CASN | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_RASN__EMI_RASN | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_WEN__EMI_WEN | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_CE0N__EMI_CE0N | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_CE1N__EMI_CE1N | MUX_CONFIG_EMI,
> +       MX28_PAD_EMI_CKE__EMI_CKE | MUX_CONFIG_EMI,
> +
> +       /* SPI2 (for flash) */
> +       MX28_PAD_SSP2_SCK__SSP2_SCK | MUX_CONFIG_SSP2,
> +       MX28_PAD_SSP2_MOSI__SSP2_CMD | MUX_CONFIG_SSP2,
> +       MX28_PAD_SSP2_MISO__SSP2_D0 | MUX_CONFIG_SSP2,
> +       MX28_PAD_SSP2_SS0__SSP2_D3 |
> +               (MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP),
> +};
> +
> +void board_init_ll(void)
> +{
> +       mxs_iomux_setup_multiple_pads(iomux_setup, ARRAY_SIZE(iomux_setup));
> +       mx28_power_init();
> +       mx28_mem_init();
> +       mx28_power_wait_pswitch();
> +}
> +
> +/* Support aparatus */
> +inline void board_init_f(unsigned long bootflag)
> +{
> +       for (;;)
> +               ;
> +}
> +
> +inline void board_init_r(gd_t *id, ulong dest_addr)
> +{
> +       for (;;)
> +               ;
> +}
> +
> +inline void lowlevel_init(void) {}
> +
> +inline void __coloured_LED_init(void) {}
> +inline void __red_LED_on(void) {}
> +void coloured_LED_init(void)
> +       __attribute__((weak, alias("__coloured_LED_init")));
> +void red_LED_on(void)
> +       __attribute__((weak, alias("__red_LED_on")));
> +void hang(void) __attribute__ ((noreturn));
> +void hang(void)
> +{
> +       for (;;)
> +               ;
> +}
> diff --git a/mmc_spl/board/denx/m28evk/power_init.c b/mmc_spl/board/denx/m28evk/power_init.c
> new file mode 100644
> index 0000000..419b452
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/power_init.c
> @@ -0,0 +1,915 @@
> +/*
> + * Freescale i.MX28 Boot PMIC init
> + *
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + * on behalf of DENX Software Engineering GmbH
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <config.h>
> +#include <asm/io.h>
> +#include <asm/arch/regs-common.h>
> +#include <asm/arch/regs-base.h>
> +#include <asm/arch/regs-clkctrl.h>
> +#include <asm/arch/regs-rtc.h>
> +#include <asm/arch/regs-power.h>
> +
> +#include "m28_init.h"
> +
> +void mx28_power_clock2xtal(void)
> +{
> +       struct mx28_clkctrl_regs *clkctrl_regs =
> +               (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
> +
> +       /* Set XTAL as CPU reference clock */
> +       writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
> +               &clkctrl_regs->hw_clkctrl_clkseq_set);
> +}
> +
> +void mx28_power_clock2pll(void)
> +{
> +       struct mx28_clkctrl_regs *clkctrl_regs =
> +               (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
> +
> +       writel(CLKCTRL_PLL0CTRL0_POWER,
> +               &clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
> +       early_delay(100);
> +       writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
> +               &clkctrl_regs->hw_clkctrl_clkseq_clr);
> +}
> +
> +void mx28_power_clear_auto_restart(void)
> +{
> +       struct mx28_rtc_regs *rtc_regs =
> +               (struct mx28_rtc_regs *)MXS_RTC_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)
> +               ;
> +
> +       /*
> +        * Due to the hardware design bug of mx28 EVK-A
> +        * we need to set the AUTO_RESTART bit.
> +        */
> +       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)
> +               ;
> +}
> +
> +void mx28_power_set_linreg(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +void mx28_power_setup_5v_detect(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +void mx28_src_power_init(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +       early_delay(30);
> +       clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
> +}
> +
> +void mx28_power_init_4p2_params(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +void mx28_enable_4p2_dcdc_input(int xfer)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +               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);
> +       }
> +
> +       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)
> +               clrbits_le32(&power_regs->hw_power_ctrl,
> +                               POWER_CTRL_VBUS_VALID_IRQ);
> +
> +       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)
> +               clrbits_le32(&power_regs->hw_power_ctrl,
> +                               POWER_CTRL_VDD5V_DROOP_IRQ);
> +
> +       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);
> +}
> +
> +void mx28_power_init_4p2_regulator(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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 */
> +       writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
> +               &power_regs->hw_power_5vctrl_clr);
> +
> +       /*
> +        * 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
> +        */
> +       mx28_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);
> +               writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
> +                       &power_regs->hw_power_5vctrl_set);
> +               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;
> +                               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);
> +                               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);
> +}
> +
> +void mx28_power_init_dcdc_4p2_source(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +
> +       if (!(readl(&power_regs->hw_power_dcdc4p2) &
> +               POWER_DCDC4P2_ENABLE_DCDC)) {
> +               hang();
> +       }
> +
> +       mx28_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);
> +               writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
> +                       &power_regs->hw_power_5vctrl_set);
> +       }
> +}
> +
> +void mx28_power_enable_4p2(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +
> +       mx28_power_init_4p2_params();
> +       mx28_power_init_4p2_regulator();
> +
> +       /* Shutdown battery (none present) */
> +       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);
> +
> +       mx28_power_init_dcdc_4p2_source();
> +
> +       writel(vdddctrl, &power_regs->hw_power_vdddctrl);
> +       early_delay(20);
> +       writel(vddactrl, &power_regs->hw_power_vddactrl);
> +       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);
> +}
> +
> +void mx28_boot_valid_5v(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +
> +       mx28_power_enable_4p2();
> +}
> +
> +void mx28_powerdown(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +void mx28_handle_5v_conflict(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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) {
> +                       mx28_powerdown();
> +                       break;
> +               }
> +
> +               if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
> +                       mx28_boot_valid_5v();
> +                       break;
> +               } else {
> +                       mx28_powerdown();
> +                       break;
> +               }
> +       }
> +}
> +
> +int mx28_get_batt_volt(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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;
> +}
> +
> +int mx28_is_batt_ready(void)
> +{
> +       return (mx28_get_batt_volt() >= 3600);
> +}
> +
> +void mx28_5v_boot(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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) {
> +               mx28_boot_valid_5v();
> +               return;
> +       }
> +
> +       early_delay(1000);
> +       if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
> +               mx28_boot_valid_5v();
> +               return;
> +       }
> +
> +       mx28_handle_5v_conflict();
> +}
> +
> +void mx28_init_batt_bo(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +void mx28_switch_vddd_to_dcdc_source(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +int mx28_is_batt_good(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +       uint32_t volt;
> +
> +       volt = readl(&power_regs->hw_power_battmonitor);
> +       volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
> +       volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
> +       volt *= 8;
> +
> +       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);
> +       writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
> +               &power_regs->hw_power_5vctrl_clr);
> +
> +       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);
> +       writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
> +               &power_regs->hw_power_5vctrl_clr);
> +
> +       early_delay(500000);
> +
> +       volt = readl(&power_regs->hw_power_battmonitor);
> +       volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
> +       volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
> +       volt *= 8;
> +
> +       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;
> +}
> +
> +void mx28_power_configure_power_source(void)
> +{
> +       mx28_src_power_init();
> +
> +       mx28_5v_boot();
> +       mx28_power_clock2pll();
> +
> +       mx28_init_batt_bo();
> +       mx28_switch_vddd_to_dcdc_source();
> +}
> +
> +void mx28_enable_output_rail_protection(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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);
> +}
> +
> +int mx28_get_vddio_power_source_off(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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_VDDDCTRL_LINREG_OFFSET_0STEPS) {
> +                               return 1;
> +                       }
> +               }
> +
> +               if (!(readl(&power_regs->hw_power_5vctrl) &
> +                       POWER_5VCTRL_ENABLE_DCDC)) {
> +                       if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
> +                               POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
> +                               return 1;
> +                       }
> +               }
> +       }
> +
> +       return 0;
> +
> +}
> +
> +int mx28_get_vddd_power_source_off(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_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;
> +}
> +
> +void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +       uint32_t cur_target, diff, bo_int = 0;
> +       uint32_t powered_by_linreg = 0;
> +
> +       new_brownout = new_target - new_brownout;
> +
> +       cur_target = readl(&power_regs->hw_power_vddioctrl);
> +       cur_target &= POWER_VDDIOCTRL_TRG_MASK;
> +       cur_target *= 50;       /* 50 mV step*/
> +       cur_target += 2800;     /* 2800 mV lowest */
> +
> +       powered_by_linreg = mx28_get_vddio_power_source_off();
> +       if (new_target > cur_target) {
> +
> +               if (powered_by_linreg) {
> +                       bo_int = readl(&power_regs->hw_power_vddioctrl);
> +                       clrbits_le32(&power_regs->hw_power_vddioctrl,
> +                                       POWER_CTRL_ENIRQ_VDDIO_BO);
> +               }
> +
> +               setbits_le32(&power_regs->hw_power_vddioctrl,
> +                               POWER_VDDIOCTRL_BO_OFFSET_MASK);
> +               do {
> +                       if (new_target - cur_target > 100)
> +                               diff = cur_target + 100;
> +                       else
> +                               diff = new_target;
> +
> +                       diff -= 2800;
> +                       diff /= 50;
> +
> +                       clrsetbits_le32(&power_regs->hw_power_vddioctrl,
> +                               POWER_VDDIOCTRL_TRG_MASK, diff);
> +
> +                       if (powered_by_linreg)
> +                               early_delay(1500);
> +                       else {
> +                               while (!(readl(&power_regs->hw_power_sts) &
> +                                       POWER_STS_DC_OK))
> +                                       ;
> +
> +                       }
> +
> +                       cur_target = readl(&power_regs->hw_power_vddioctrl);
> +                       cur_target &= POWER_VDDIOCTRL_TRG_MASK;
> +                       cur_target *= 50;       /* 50 mV step*/
> +                       cur_target += 2800;     /* 2800 mV lowest */
> +               } while (new_target > cur_target);
> +
> +               if (powered_by_linreg) {
> +                       writel(POWER_CTRL_VDDIO_BO_IRQ,
> +                               &power_regs->hw_power_ctrl_clr);
> +                       if (bo_int & POWER_CTRL_ENIRQ_VDDIO_BO)
> +                               setbits_le32(&power_regs->hw_power_vddioctrl,
> +                                               POWER_CTRL_ENIRQ_VDDIO_BO);
> +               }
> +       } else {
> +               do {
> +                       if (cur_target - new_target > 100)
> +                               diff = cur_target - 100;
> +                       else
> +                               diff = new_target;
> +
> +                       diff -= 2800;
> +                       diff /= 50;
> +
> +                       clrsetbits_le32(&power_regs->hw_power_vddioctrl,
> +                               POWER_VDDIOCTRL_TRG_MASK, diff);
> +
> +                       if (powered_by_linreg)
> +                               early_delay(1500);
> +                       else {
> +                               while (!(readl(&power_regs->hw_power_sts) &
> +                                       POWER_STS_DC_OK))
> +                                       ;
> +
> +                       }
> +
> +                       cur_target = readl(&power_regs->hw_power_vddioctrl);
> +                       cur_target &= POWER_VDDIOCTRL_TRG_MASK;
> +                       cur_target *= 50;       /* 50 mV step*/
> +                       cur_target += 2800;     /* 2800 mV lowest */
> +               } while (new_target < cur_target);
> +       }
> +
> +       clrsetbits_le32(&power_regs->hw_power_vddioctrl,
> +                       POWER_VDDDCTRL_BO_OFFSET_MASK,
> +                       new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
> +}
> +
> +void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +       uint32_t cur_target, diff, bo_int = 0;
> +       uint32_t powered_by_linreg = 0;
> +
> +       new_brownout = new_target - new_brownout;
> +
> +       cur_target = readl(&power_regs->hw_power_vdddctrl);
> +       cur_target &= POWER_VDDDCTRL_TRG_MASK;
> +       cur_target *= 25;       /* 25 mV step*/
> +       cur_target += 800;      /* 800 mV lowest */
> +
> +       powered_by_linreg = mx28_get_vddd_power_source_off();
> +       if (new_target > cur_target) {
> +               if (powered_by_linreg) {
> +                       bo_int = readl(&power_regs->hw_power_vdddctrl);
> +                       clrbits_le32(&power_regs->hw_power_vdddctrl,
> +                                       POWER_CTRL_ENIRQ_VDDD_BO);
> +               }
> +
> +               setbits_le32(&power_regs->hw_power_vdddctrl,
> +                               POWER_VDDDCTRL_BO_OFFSET_MASK);
> +
> +               do {
> +                       if (new_target - cur_target > 100)
> +                               diff = cur_target + 100;
> +                       else
> +                               diff = new_target;
> +
> +                       diff -= 800;
> +                       diff /= 25;
> +
> +                       clrsetbits_le32(&power_regs->hw_power_vdddctrl,
> +                               POWER_VDDDCTRL_TRG_MASK, diff);
> +
> +                       if (powered_by_linreg)
> +                               early_delay(1500);
> +                       else {
> +                               while (!(readl(&power_regs->hw_power_sts) &
> +                                       POWER_STS_DC_OK))
> +                                       ;
> +
> +                       }
> +
> +                       cur_target = readl(&power_regs->hw_power_vdddctrl);
> +                       cur_target &= POWER_VDDDCTRL_TRG_MASK;
> +                       cur_target *= 25;       /* 25 mV step*/
> +                       cur_target += 800;      /* 800 mV lowest */
> +               } while (new_target > cur_target);
> +
> +               if (powered_by_linreg) {
> +                       writel(POWER_CTRL_VDDD_BO_IRQ,
> +                               &power_regs->hw_power_ctrl_clr);
> +                       if (bo_int & POWER_CTRL_ENIRQ_VDDD_BO)
> +                               setbits_le32(&power_regs->hw_power_vdddctrl,
> +                                               POWER_CTRL_ENIRQ_VDDD_BO);
> +               }
> +       } else {
> +               do {
> +                       if (cur_target - new_target > 100)
> +                               diff = cur_target - 100;
> +                       else
> +                               diff = new_target;
> +
> +                       diff -= 800;
> +                       diff /= 25;
> +
> +                       clrsetbits_le32(&power_regs->hw_power_vdddctrl,
> +                                       POWER_VDDDCTRL_TRG_MASK, diff);
> +
> +                       if (powered_by_linreg)
> +                               early_delay(1500);
> +                       else {
> +                               while (!(readl(&power_regs->hw_power_sts) &
> +                                       POWER_STS_DC_OK))
> +                                       ;
> +
> +                       }
> +
> +                       cur_target = readl(&power_regs->hw_power_vdddctrl);
> +                       cur_target &= POWER_VDDDCTRL_TRG_MASK;
> +                       cur_target *= 25;       /* 25 mV step*/
> +                       cur_target += 800;      /* 800 mV lowest */
> +               } while (new_target < cur_target);
> +       }
> +
> +       clrsetbits_le32(&power_regs->hw_power_vdddctrl,
> +                       POWER_VDDDCTRL_BO_OFFSET_MASK,
> +                       new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
> +}
> +
> +void mx28_power_init(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +
> +       mx28_power_clock2xtal();
> +       mx28_power_clear_auto_restart();
> +       mx28_power_set_linreg();
> +       mx28_power_setup_5v_detect();
> +       mx28_power_configure_power_source();
> +       mx28_enable_output_rail_protection();
> +
> +       mx28_power_set_vddio(3300, 3150);
> +
> +       mx28_power_set_vddd(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);
> +
> +       early_delay(1000);
> +}
> +
> +void mx28_power_wait_pswitch(void)
> +{
> +       struct mx28_power_regs *power_regs =
> +               (struct mx28_power_regs *)MXS_POWER_BASE;
> +
> +       while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
> +               ;
> +}
> diff --git a/mmc_spl/board/denx/m28evk/start.S b/mmc_spl/board/denx/m28evk/start.S
> new file mode 100644
> index 0000000..48c2be6
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/start.S
> @@ -0,0 +1,402 @@
> +/*
> + *  armboot - Startup Code for ARM926EJS CPU-core
> + *
> + *  Copyright (c) 2003  Texas Instruments
> + *
> + *  ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
> + *
> + *  Copyright (c) 2001 Marius Groger <mag@sysgo.de>
> + *  Copyright (c) 2002 Alex Zupke <azu@sysgo.de>
> + *  Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
> + *  Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
> + *  Copyright (c) 2003 Kshitij <kshitij@ti.com>
> + *  Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net>
> + *
> + * Change to support call back into iMX28 bootrom
> + * Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com>
> + * on behalf of DENX Software Engineering GmbH
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <asm-offsets.h>
> +#include <config.h>
> +#include <common.h>
> +#include <version.h>
> +
> +#if defined(CONFIG_OMAP1610)
> +#include <./configs/omap1510.h>
> +#elif defined(CONFIG_OMAP730)
> +#include <./configs/omap730.h>
> +#endif
> +
> +/*
> + *************************************************************************
> + *
> + * Jump vector table as in table 3.1 in [1]
> + *
> + *************************************************************************
> + */
> +
> +
> +.globl _start
> +_start:
> +       b       reset
> +#ifdef CONFIG_SPL_BUILD
> +/* No exception handlers in preloader */
> +       ldr     pc, _hang
> +       ldr     pc, _hang
> +       ldr     pc, _hang
> +       ldr     pc, _hang
> +       b       reset
> +       ldr     pc, _hang
> +       ldr     pc, _hang
> +
> +_hang:
> +       .word   do_hang
> +/* pad to 64 byte boundary */
> +       .word   0x12345678
> +       .word   0x12345678
> +       .word   0x12345678
> +       .word   0x12345678
> +       .word   0x12345678
> +       .word   0x12345678
> +       .word   0x12345678
> +#else
> +       ldr     pc, _undefined_instruction
> +       ldr     pc, _software_interrupt
> +       ldr     pc, _prefetch_abort
> +       ldr     pc, _data_abort
> +       ldr     pc, _not_used
> +       ldr     pc, _irq
> +       ldr     pc, _fiq
> +
> +_undefined_instruction:
> +       .word undefined_instruction
> +_software_interrupt:
> +       .word software_interrupt
> +_prefetch_abort:
> +       .word prefetch_abort
> +_data_abort:
> +       .word data_abort
> +_not_used:
> +       .word not_used
> +_irq:
> +       .word irq
> +_fiq:
> +       .word fiq
> +
> +#endif /* CONFIG_SPL_BUILD */
> +       .balignl 16,0xdeadbeef
> +
> +
> +/*
> + *************************************************************************
> + *
> + * Startup Code (reset vector)
> + *
> + * do important init only if we don't start from memory!
> + * setup Memory and board specific bits prior to relocation.
> + * relocate armboot to ram
> + * setup stack
> + *
> + *************************************************************************
> + */
> +
> +.globl _TEXT_BASE
> +_TEXT_BASE:
> +       .word   CONFIG_SYS_TEXT_BASE
> +
> +/*
> + * These are defined in the board-specific linker script.
> + * Subtracting _start from them lets the linker put their
> + * relative position in the executable instead of leaving
> + * them null.
> + */
> +.globl _bss_start_ofs
> +_bss_start_ofs:
> +       .word __bss_start - _start
> +
> +.globl _bss_end_ofs
> +_bss_end_ofs:
> +       .word __bss_end__ - _start
> +
> +.globl _end_ofs
> +_end_ofs:
> +       .word _end - _start
> +
> +#ifdef CONFIG_USE_IRQ
> +/* IRQ stack memory (calculated at run-time) */
> +.globl IRQ_STACK_START
> +IRQ_STACK_START:
> +       .word   0x0badc0de
> +
> +/* IRQ stack memory (calculated at run-time) */
> +.globl FIQ_STACK_START
> +FIQ_STACK_START:
> +       .word 0x0badc0de
> +#endif
> +
> +/* IRQ stack memory (calculated at run-time) + 8 bytes */
> +.globl IRQ_STACK_START_IN
> +IRQ_STACK_START_IN:
> +       .word   0x0badc0de
> +
> +/*
> + * the actual reset code
> + */
> +
> +reset:
> +       /*
> +        * Store all registers on old stack pointer, this will allow us later to
> +        * return to the BootROM and let the BootROM load U-Boot into RAM.
> +        */
> +       push    {r0-r12,r14}
> +
> +       /*
> +        * set the cpu to SVC32 mode
> +        */
> +       mrs     r0,cpsr
> +       bic     r0,r0,#0x1f
> +       orr     r0,r0,#0xd3
> +       msr     cpsr,r0
> +
> +       /*
> +        * we do sys-critical inits only at reboot,
> +        * not when booting from ram!
> +        */
> +#ifndef CONFIG_SKIP_LOWLEVEL_INIT
> +       bl      cpu_init_crit
> +#endif
> +
> +       bl      board_init_ll
> +
> +       pop     {r0-r12,r14}
> +       bx      lr
> +
> +/*
> + *************************************************************************
> + *
> + * CPU_init_critical registers
> + *
> + * setup important registers
> + * setup memory timing
> + *
> + *************************************************************************
> + */
> +#ifndef CONFIG_SKIP_LOWLEVEL_INIT
> +cpu_init_crit:
> +       /*
> +        * flush v4 I/D caches
> +        */
> +       mov     r0, #0
> +       mcr     p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
> +       mcr     p15, 0, r0, c8, c7, 0   /* flush v4 TLB */
> +
> +       /*
> +        * disable MMU stuff and caches
> +        */
> +       mrc     p15, 0, r0, c1, c0, 0
> +       bic     r0, r0, #0x00002300     /* clear bits 13, 9:8 (--V- --RS) */
> +       bic     r0, r0, #0x00000087     /* clear bits 7, 2:0 (B--- -CAM) */
> +       orr     r0, r0, #0x00000002     /* set bit 2 (A) Align */
> +       orr     r0, r0, #0x00001000     /* set bit 12 (I) I-Cache */
> +       mcr     p15, 0, r0, c1, c0, 0
> +
> +       /*
> +        * Go setup Memory and board specific bits prior to relocation.
> +        */
> +       mov     ip, lr          /* perserve link reg across call */
> +       bl      lowlevel_init   /* go setup pll,mux,memory */
> +       mov     lr, ip          /* restore link */
> +       mov     pc, lr          /* back to my caller */
> +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
> +
> +#ifndef CONFIG_SPL_BUILD
> +/*
> + *************************************************************************
> + *
> + * Interrupt handling
> + *
> + *************************************************************************
> + */
> +
> +@
> +@ IRQ stack frame.
> +@
> +#define S_FRAME_SIZE   72
> +
> +#define S_OLD_R0       68
> +#define S_PSR          64
> +#define S_PC           60
> +#define S_LR           56
> +#define S_SP           52
> +
> +#define S_IP           48
> +#define S_FP           44
> +#define S_R10          40
> +#define S_R9           36
> +#define S_R8           32
> +#define S_R7           28
> +#define S_R6           24
> +#define S_R5           20
> +#define S_R4           16
> +#define S_R3           12
> +#define S_R2           8
> +#define S_R1           4
> +#define S_R0           0
> +
> +#define MODE_SVC 0x13
> +#define I_BIT   0x80
> +
> +/*
> + * use bad_save_user_regs for abort/prefetch/undef/swi ...
> + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
> + */
> +
> +       .macro  bad_save_user_regs
> +       @ carve out a frame on current user stack
> +       sub     sp, sp, #S_FRAME_SIZE
> +       stmia   sp, {r0 - r12}  @ Save user registers (now in svc mode) r0-r12
> +       ldr     r2, IRQ_STACK_START_IN
> +       @ get values for "aborted" pc and cpsr (into parm regs)
> +       ldmia   r2, {r2 - r3}
> +       add     r0, sp, #S_FRAME_SIZE           @ grab pointer to old stack
> +       add     r5, sp, #S_SP
> +       mov     r1, lr
> +       stmia   r5, {r0 - r3}   @ save sp_SVC, lr_SVC, pc, cpsr
> +       mov     r0, sp          @ save current stack into r0 (param register)
> +       .endm
> +
> +       .macro  irq_save_user_regs
> +       sub     sp, sp, #S_FRAME_SIZE
> +       stmia   sp, {r0 - r12}                  @ Calling r0-r12
> +       @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
> +       add     r8, sp, #S_PC
> +       stmdb   r8, {sp, lr}^           @ Calling SP, LR
> +       str     lr, [r8, #0]            @ Save calling PC
> +       mrs     r6, spsr
> +       str     r6, [r8, #4]            @ Save CPSR
> +       str     r0, [r8, #8]            @ Save OLD_R0
> +       mov     r0, sp
> +       .endm
> +
> +       .macro  irq_restore_user_regs
> +       ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
> +       mov     r0, r0
> +       ldr     lr, [sp, #S_PC]                 @ Get PC
> +       add     sp, sp, #S_FRAME_SIZE
> +       subs    pc, lr, #4              @ return & move spsr_svc into cpsr
> +       .endm
> +
> +       .macro get_bad_stack
> +       ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack
> +
> +       str     lr, [r13]       @ save caller lr in position 0 of saved stack
> +       mrs     lr, spsr        @ get the spsr
> +       str     lr, [r13, #4]   @ save spsr in position 1 of saved stack
> +       mov     r13, #MODE_SVC  @ prepare SVC-Mode
> +       @ msr   spsr_c, r13
> +       msr     spsr, r13       @ switch modes, make sure moves will execute
> +       mov     lr, pc          @ capture return pc
> +       movs    pc, lr          @ jump to next instruction & switch modes.
> +       .endm
> +
> +       .macro get_irq_stack                    @ setup IRQ stack
> +       ldr     sp, IRQ_STACK_START
> +       .endm
> +
> +       .macro get_fiq_stack                    @ setup FIQ stack
> +       ldr     sp, FIQ_STACK_START
> +       .endm
> +#endif /* CONFIG_SPL_BUILD */
> +
> +/*
> + * exception handlers
> + */
> +#ifdef CONFIG_SPL_BUILD
> +       .align  5
> +do_hang:
> +       ldr     sp, _TEXT_BASE                  /* switch to abort stack */
> +1:
> +       bl      1b                              /* hang and never return */
> +#else  /* !CONFIG_SPL_BUILD */
> +       .align  5
> +undefined_instruction:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_undefined_instruction
> +
> +       .align  5
> +software_interrupt:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_software_interrupt
> +
> +       .align  5
> +prefetch_abort:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_prefetch_abort
> +
> +       .align  5
> +data_abort:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_data_abort
> +
> +       .align  5
> +not_used:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_not_used
> +
> +#ifdef CONFIG_USE_IRQ
> +
> +       .align  5
> +irq:
> +       get_irq_stack
> +       irq_save_user_regs
> +       bl      do_irq
> +       irq_restore_user_regs
> +
> +       .align  5
> +fiq:
> +       get_fiq_stack
> +       /* someone ought to write a more effiction fiq_save_user_regs */
> +       irq_save_user_regs
> +       bl      do_fiq
> +       irq_restore_user_regs
> +
> +#else
> +
> +       .align  5
> +irq:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_irq
> +
> +       .align  5
> +fiq:
> +       get_bad_stack
> +       bad_save_user_regs
> +       bl      do_fiq
> +
> +#endif
> +#endif /* CONFIG_SPL_BUILD */
> diff --git a/mmc_spl/board/denx/m28evk/u-boot.bd b/mmc_spl/board/denx/m28evk/u-boot.bd
> new file mode 100644
> index 0000000..3ddffbc
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/u-boot.bd
> @@ -0,0 +1,14 @@
> +sources {
> +       u_boot_spl="mmc_spl/u-boot-spl.bin";
> +       u_boot="u-boot.bin";
> +}
> +
> +section (0) {
> +        load u_boot_spl > 0x0000;
> +        load ivt (entry = 0x0014) > 0x8000;
> +       hab call 0x8000;
> +
> +        load u_boot > 0x40000100;
> +        load ivt (entry = 0x40000100) > 0x8000;
> +       hab call 0x8000;
> +}
> diff --git a/mmc_spl/board/denx/m28evk/u-boot.lds b/mmc_spl/board/denx/m28evk/u-boot.lds
> new file mode 100644
> index 0000000..f491bb5
> --- /dev/null
> +++ b/mmc_spl/board/denx/m28evk/u-boot.lds
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
> + * on behalf of DENX Software Engineering GmbH
> + *
> + * January 2004 - Changed to support H4 device
> + * Copyright (c) 2004-2008 Texas Instruments
> + *
> + * (C) Copyright 2002
> + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * 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 program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
> +OUTPUT_ARCH(arm)
> +ENTRY(_start)
> +SECTIONS
> +{
> +       . = 0x00000000;
> +
> +       . = ALIGN(4);
> +       .text   :
> +       {
> +               start.o (.text)
> +               *(.text)
> +       }
> +
> +       . = ALIGN(4);
> +       .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
> +
> +       . = ALIGN(4);
> +       .data : {
> +               *(.data)
> +       }
> +
> +       . = ALIGN(4);
> +       __u_boot_cmd_start = .;
> +       .u_boot_cmd : { *(.u_boot_cmd) }
> +       __u_boot_cmd_end = .;
> +
> +       . = ALIGN(4);
> +
> +       .rel.dyn : {
> +               __rel_dyn_start = .;
> +               *(.rel*)
> +               __rel_dyn_end = .;
> +       }
> +
> +       .dynsym : {
> +               __dynsym_start = .;
> +               *(.dynsym)
> +       }
> +
> +       _end = .;
> +
> +       .bss __rel_dyn_start (OVERLAY) : {
> +               __bss_start = .;
> +               *(.bss)
> +                . = ALIGN(4);
> +               __bss_end__ = .;
> +       }
> +
> +       /DISCARD/ : { *(.bss*) }
> +       /DISCARD/ : { *(.dynstr*) }
> +       /DISCARD/ : { *(.dynsym*) }
> +       /DISCARD/ : { *(.dynamic*) }
> +       /DISCARD/ : { *(.hash*) }
> +       /DISCARD/ : { *(.plt*) }
> +       /DISCARD/ : { *(.interp*) }
> +       /DISCARD/ : { *(.gnu*) }
> +}
> --
> 1.7.5.4
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot



--
with warm regards,
Chander Kashyap
Wolfgang Denk - Sept. 9, 2011, 7:33 a.m.
Dear Chander Kashyap,

In message <CANuQgHE26ewWMXqW=wwhRy6J8n3bzmvKKRVCnm_Y+79x3oKVfw@mail.gmail.com> you wrote:
> Dear Marek Vasut,
> Please use newly added spl framework to add mmc spl support.

Please STOP top posting / full quoting!!!

Please read http://www.netmeister.org/news/learn2quote.html

It makes _zero_ sense to quote 2500 lines just for your single line
remark.

And please always send plain text only; never use HTML.

Thanks.

Wolfgang Denk
Marek Vasut - Sept. 9, 2011, 12:49 p.m.
On Friday, September 09, 2011 07:02:24 AM Chander Kashyap wrote:
> Dear Marek Vasut,
> Please use newly added spl framework to add mmc spl support.
> 

Hi,

if you could possibly elaborate more on this matter, I'd be grateful. Especially 
how am I supposed to convert it to new SPL framework. I don't see many examples, 
only an empty directory.

Cheers
Chander Kashyap - Sept. 9, 2011, 1:14 p.m.
2011/9/9 Marek Vasut <marek.vasut@gmail.com>:
> On Friday, September 09, 2011 07:02:24 AM Chander Kashyap wrote:
>> Dear Marek Vasut,
>> Please use newly added spl framework to add mmc spl support.
>>
>
> Hi,
>
> if you could possibly elaborate more on this matter, I'd be grateful. Especially
> how am I supposed to convert it to new SPL framework. I don't see many examples,
> only an empty directory.
Please see the implementation of origen board(board/samsung/origen).
Its newly added.
May be you can move mmc_spl/board/denx/m28evk/* to board/denx/m28evk/*
define CONFIG_SPL_LDSCRIPT to the ldscript you want to use (Please
read spl/Makefile line 64 onward).
>
> Cheers
>
Marek Vasut - Sept. 10, 2011, 8:58 p.m.
On Friday, September 09, 2011 03:14:06 PM Chander Kashyap wrote:
> 2011/9/9 Marek Vasut <marek.vasut@gmail.com>:
> > On Friday, September 09, 2011 07:02:24 AM Chander Kashyap wrote:
> >> Dear Marek Vasut,
> >> Please use newly added spl framework to add mmc spl support.
> > 
> > Hi,
> > 
> > if you could possibly elaborate more on this matter, I'd be grateful.
> > Especially how am I supposed to convert it to new SPL framework. I don't
> > see many examples, only an empty directory.
> 
> Please see the implementation of origen board(board/samsung/origen).
> Its newly added.
> May be you can move mmc_spl/board/denx/m28evk/* to board/denx/m28evk/*
> define CONFIG_SPL_LDSCRIPT to the ldscript you want to use (Please
> read spl/Makefile line 64 onward).

Ok, I went through it (partly). Why do you create executables with .exe suffix 
there ? Is that some kind of a new trend in embedded linux industry?

> 
> > Cheers
Marek Vasut - Sept. 10, 2011, 9:04 p.m.
On Saturday, September 10, 2011 10:58:48 PM Marek Vasut wrote:
> On Friday, September 09, 2011 03:14:06 PM Chander Kashyap wrote:
> > 2011/9/9 Marek Vasut <marek.vasut@gmail.com>:
> > > On Friday, September 09, 2011 07:02:24 AM Chander Kashyap wrote:
> > >> Dear Marek Vasut,
> > >> Please use newly added spl framework to add mmc spl support.
> > > 
> > > Hi,
> > > 
> > > if you could possibly elaborate more on this matter, I'd be grateful.
> > > Especially how am I supposed to convert it to new SPL framework. I
> > > don't see many examples, only an empty directory.
> > 
> > Please see the implementation of origen board(board/samsung/origen).
> > Its newly added.
> > May be you can move mmc_spl/board/denx/m28evk/* to board/denx/m28evk/*
> > define CONFIG_SPL_LDSCRIPT to the ldscript you want to use (Please
> > read spl/Makefile line 64 onward).
> 
> Ok, I went through it (partly). Why do you create executables with .exe
> suffix there ? Is that some kind of a new trend in embedded linux
> industry?

Oh, one more thing -- is it possible to use custom start.S with the new "spl 
framework"? I somehow need it.

Thanks!

> 
> > > Cheers

Patch

diff --git a/mmc_spl/board/denx/m28evk/Makefile b/mmc_spl/board/denx/m28evk/Makefile
new file mode 100644
index 0000000..c08eac9
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/Makefile
@@ -0,0 +1,102 @@ 
+#
+# (C) Copyright 2006-2007
+# Stefan Roese, DENX Software Engineering, sr@denx.de.
+#
+# (C) Copyright 2008
+# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
+#
+# (C) Copyright 2011
+# Chander Kashyap, Samsung Electronics, <k.chander@samsung.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+CONFIG_MMC_SPL	= y
+
+include $(TOPDIR)/config.mk
+
+LDSCRIPT= $(TOPDIR)/mmc_spl/board/$(BOARDDIR)/u-boot.lds
+LDFLAGS	= -Bstatic -T $(mmcobj)u-boot.lds -Ttext 0x0 $(PLATFORM_LDFLAGS)
+AFLAGS	+= -DCONFIG_MMC_SPL
+AFLAGS	+= -DCONFIG_SPL_BUILD
+CFLAGS	+= -DCONFIG_MMC_SPL
+CFLAGS	+= -DCONFIG_SPL_BUILD
+
+SOBJS	= start.o _udivsi3.o _divsi3.o
+COBJS	= mmc_boot.o iomux.o power_init.o mem_init.o div0.o
+
+SRCS	:= $($(SOBJS:.o=.S) $(COBJS:.o=.c))
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+__OBJS	:= $(SOBJS) $(COBJS)
+LNDIR	:= $(OBJTREE)/mmc_spl/board/$(BOARDDIR)
+
+mmcobj	:= $(OBJTREE)/mmc_spl/
+
+
+ALL = $(mmcobj)u-boot-spl $(mmcobj)u-boot-spl.bin  $(mmcobj)u-boot-mmc-spl.bin
+
+all:    $(obj).depend $(ALL)
+
+$(mmcobj)u-boot-mmc-spl.bin:	$(mmcobj)u-boot-spl.bin
+	cp $< $@
+
+$(mmcobj)u-boot-spl.bin:	$(mmcobj)u-boot-spl
+	$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
+
+$(mmcobj)u-boot-spl:	$(OBJS) $(mmcobj)u-boot.lds
+	cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) \
+		-Map $(mmcobj)u-boot-spl.map \
+		-o $(mmcobj)u-boot-spl
+
+$(mmcobj)u-boot.lds: $(LDSCRIPT)
+	$(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
+
+# create symbolic links for common files
+
+# from cpu directory
+iomux.c:
+	@rm -f $@
+	@ln -s $(TOPDIR)/arch/arm/cpu/arm926ejs/mx28/iomux.c $@
+
+_udivsi3.S:
+	@rm -f $@
+	@ln -s $(TOPDIR)/arch/arm/lib/_udivsi3.S $@
+
+_divsi3.S:
+	@rm -f $@
+	@ln -s $(TOPDIR)/arch/arm/lib/_divsi3.S $@
+
+div0.c:
+	@rm -f $@
+	@ln -s $(TOPDIR)/arch/arm/lib/div0.c $@
+
+#########################################################################
+
+$(obj)%.o:	%.S
+	$(CC) $(AFLAGS) -c -o $@ $<
+
+$(obj)%.o:	%.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/mmc_spl/board/denx/m28evk/m28_init.h b/mmc_spl/board/denx/m28evk/m28_init.h
new file mode 100644
index 0000000..7f569e0
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/m28_init.h
@@ -0,0 +1,36 @@ 
+/*
+ * Freescale i.MX28 SPL functions
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef	__M28_INIT_H__
+#define	__M28_INIT_H__
+
+void early_delay(int delay);
+
+void mx28_power_init(void);
+void mx28_power_wait_pswitch(void);
+
+void mx28_mem_init(void);
+
+#endif	/* __M28_INIT_H__ */
diff --git a/mmc_spl/board/denx/m28evk/mem_init.c b/mmc_spl/board/denx/m28evk/mem_init.c
new file mode 100644
index 0000000..4cd6fba
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/mem_init.c
@@ -0,0 +1,218 @@ 
+/*
+ * Freescale i.MX28 RAM init
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/iomux-mx28.h>
+#include <asm/arch/regs-common.h>
+#include <asm/arch/regs-base.h>
+#include <asm/arch/regs-clkctrl.h>
+#include <asm/arch/regs-pinctrl.h>
+#include <asm/arch/regs-rtc.h>
+#include <asm/arch/regs-power.h>
+
+#include "m28_init.h"
+
+uint32_t dram_vals[] = {
+	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, 0x05060302, 0x06005003, 0x0a0000c8,
+	0x02009c40, 0x0000030c, 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, 0xf5014b27, 0xf5014b27, 0xf5014b27, 0xf5014b27,
+	0x07000300, 0x07000300, 0x07000300, 0x07000300, 0x00000006,
+	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, 0x00020304, 0x00000004,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x01010000, 0x01000000, 0x03030000, 0x00010303,
+	0x01020202, 0x00000000, 0x02040303, 0x21002103, 0x00061200,
+	0x06120612, 0x04320432, 0x04320432, 0x00040004, 0x00040004,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010001
+};
+
+void init_m28_200mhz_ddr2(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dram_vals); i++)
+		writel(dram_vals[i], MXS_DRAM_BASE + (4 * i));
+}
+
+void mx28_mem_init_clock(void)
+{
+	struct mx28_clkctrl_regs *clkctrl_regs =
+		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
+
+	/* Gate EMI clock */
+	writel(CLKCTRL_FRAC0_CLKGATEEMI,
+		&clkctrl_regs->hw_clkctrl_frac0_set);
+
+	/* EMI = 205MHz */
+	writel(CLKCTRL_FRAC0_EMIFRAC_MASK,
+		&clkctrl_regs->hw_clkctrl_frac0_set);
+	writel((0x2a << CLKCTRL_FRAC0_EMIFRAC_OFFSET) &
+		CLKCTRL_FRAC0_EMIFRAC_MASK,
+		&clkctrl_regs->hw_clkctrl_frac0_clr);
+
+	/* Ungate EMI clock */
+	writel(CLKCTRL_FRAC0_CLKGATEEMI,
+		&clkctrl_regs->hw_clkctrl_frac0_clr);
+
+	early_delay(11000);
+
+	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);
+
+	early_delay(10000);
+}
+
+void mx28_mem_setup_cpu_and_hbus(void)
+{
+	struct mx28_clkctrl_regs *clkctrl_regs =
+		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
+
+	/* CPU = 454MHz and ungate CPU clock */
+	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0,
+		CLKCTRL_FRAC0_CPUFRAC_MASK | CLKCTRL_FRAC0_CLKGATECPU,
+		19 << CLKCTRL_FRAC0_CPUFRAC_OFFSET);
+
+	/* 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);
+
+	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);
+}
+
+void mx28_mem_setup_vdda(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+void mx28_mem_setup_vddd(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+
+	writel((0x1c << POWER_VDDDCTRL_TRG_OFFSET) |
+		(0x7 << POWER_VDDDCTRL_BO_OFFSET_OFFSET) |
+		POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW,
+		&power_regs->hw_power_vdddctrl);
+}
+
+void mx28_mem_init(void)
+{
+	struct mx28_clkctrl_regs *clkctrl_regs =
+		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
+	struct mx28_pinctrl_regs *pinctrl_regs =
+		(struct mx28_pinctrl_regs *)MXS_PINCTRL_BASE;
+
+	/* Set DDR2 mode */
+	writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2,
+		&pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set);
+
+	/* Power up PLL0 */
+	writel(CLKCTRL_PLL0CTRL0_POWER,
+		&clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
+
+	early_delay(11000);
+
+	mx28_mem_init_clock();
+
+	mx28_mem_setup_vdda();
+
+	/*
+	 * Configure the DRAM registers
+	 */
+
+	/* Clear START bit from DRAM_CTL16 */
+	clrbits_le32(MXS_DRAM_BASE + 0x40, 1);
+
+	init_m28_200mhz_ddr2();
+
+	/* Clear SREFRESH bit from DRAM_CTL17 */
+	clrbits_le32(MXS_DRAM_BASE + 0x44, 1);
+
+	/* Set START bit in DRAM_CTL16 */
+	setbits_le32(MXS_DRAM_BASE + 0x40, 1);
+
+	/* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */
+	while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20)))
+		;
+
+	mx28_mem_setup_vddd();
+
+	early_delay(10000);
+
+	mx28_mem_setup_cpu_and_hbus();
+}
diff --git a/mmc_spl/board/denx/m28evk/mmc_boot.c b/mmc_spl/board/denx/m28evk/mmc_boot.c
new file mode 100644
index 0000000..4e670ea
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/mmc_boot.c
@@ -0,0 +1,271 @@ 
+/*
+ * Freescale i.MX28 Boot setup
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/iomux-mx28.h>
+
+#include "m28_init.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.
+ */
+#define	HW_DIGCTRL_MICROSECONDS	0x8001c0c0
+void early_delay(int delay)
+{
+	uint32_t st = readl(HW_DIGCTRL_MICROSECONDS);
+	st += delay;
+	while (st > readl(HW_DIGCTRL_MICROSECONDS))
+		;
+}
+
+#define	MUX_CONFIG_LED	(MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
+#define	MUX_CONFIG_LCD	(MXS_PAD_3V3 | MXS_PAD_4MA)
+#define	MUX_CONFIG_TSC	(MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP)
+#define	MUX_CONFIG_SSP0	(MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_PULLUP)
+#define	MUX_CONFIG_SSP2	(MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP)
+#define	MUX_CONFIG_GPMI	(MXS_PAD_1V8 | MXS_PAD_4MA | MXS_PAD_NOPULL)
+#define	MUX_CONFIG_ENET	(MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP)
+#define	MUX_CONFIG_EMI	(MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL)
+
+const iomux_cfg_t iomux_setup[] = {
+	/* LED */
+	MX28_PAD_ENET0_RXD3__GPIO_4_10 | MUX_CONFIG_LED,
+
+	/* framebuffer */
+	MX28_PAD_LCD_D00__LCD_D0 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D01__LCD_D1 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D02__LCD_D2 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D03__LCD_D3 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D04__LCD_D4 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D05__LCD_D5 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D06__LCD_D6 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D07__LCD_D7 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D08__LCD_D8 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D09__LCD_D9 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D10__LCD_D10 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D11__LCD_D11 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D12__LCD_D12 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D13__LCD_D13 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D14__LCD_D14 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D15__LCD_D15 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D16__LCD_D16 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D17__LCD_D17 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D18__LCD_D18 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D19__LCD_D19 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D20__LCD_D20 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D21__LCD_D21 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D22__LCD_D22 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_D23__LCD_D23 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_RD_E__LCD_VSYNC | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_WR_RWN__LCD_HSYNC | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_RS__LCD_DOTCLK | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_CS__LCD_CS | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_VSYNC__LCD_VSYNC | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_HSYNC__LCD_HSYNC | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_DOTCLK__LCD_DOTCLK | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_ENABLE__GPIO_1_31 | MUX_CONFIG_LCD,
+	MX28_PAD_LCD_RESET__GPIO_3_30 | MUX_CONFIG_LCD,
+	MX28_PAD_PWM0__PWM_0 | MUX_CONFIG_LCD,
+
+	/* UART1 */
+	MX28_PAD_AUART0_CTS__DUART_RX,
+	MX28_PAD_AUART0_RTS__DUART_TX,
+	MX28_PAD_AUART0_TX__DUART_RTS,
+	MX28_PAD_AUART0_RX__DUART_CTS,
+
+	/* UART2 */
+	MX28_PAD_AUART1_RX__AUART1_RX,
+	MX28_PAD_AUART1_TX__AUART1_TX,
+	MX28_PAD_AUART1_RTS__AUART1_RTS,
+	MX28_PAD_AUART1_CTS__AUART1_CTS,
+
+	/* CAN */
+	MX28_PAD_GPMI_RDY2__CAN0_TX,
+	MX28_PAD_GPMI_RDY3__CAN0_RX,
+
+	/* I2C */
+	MX28_PAD_I2C0_SCL__I2C0_SCL,
+	MX28_PAD_I2C0_SDA__I2C0_SDA,
+
+	/* TSC2007 */
+	MX28_PAD_SAIF0_MCLK__GPIO_3_20 | MUX_CONFIG_TSC,
+
+	/* MMC0 */
+	MX28_PAD_SSP0_DATA0__SSP0_D0 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA1__SSP0_D1 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA2__SSP0_D2 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA3__SSP0_D3 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA4__SSP0_D4 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA5__SSP0_D5 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA6__SSP0_D6 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DATA7__SSP0_D7 | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_CMD__SSP0_CMD | MUX_CONFIG_SSP0,
+	MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT |
+		(MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL),
+	MX28_PAD_SSP0_SCK__SSP0_SCK |
+		(MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL),
+	MX28_PAD_PWM3__GPIO_3_28 | MUX_CONFIG_SSP0,	/* Power .. FIXME */
+	MX28_PAD_AUART2_CTS__GPIO_3_10,	/* WP ... FIXME */
+
+	/* GPMI NAND */
+	MX28_PAD_GPMI_D00__GPMI_D0 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D01__GPMI_D1 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D02__GPMI_D2 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D03__GPMI_D3 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D04__GPMI_D4 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D05__GPMI_D5 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D06__GPMI_D6 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_D07__GPMI_D7 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_CE0N__GPMI_CE0N | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_RDY0__GPMI_READY0 | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_RDN__GPMI_RDN |
+		(MXS_PAD_1V8 | MXS_PAD_8MA | MXS_PAD_PULLUP),
+	MX28_PAD_GPMI_WRN__GPMI_WRN | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_ALE__GPMI_ALE | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_CLE__GPMI_CLE | MUX_CONFIG_GPMI,
+	MX28_PAD_GPMI_RESETN__GPMI_RESETN | MUX_CONFIG_GPMI,
+
+	/* FEC Ethernet */
+	MX28_PAD_ENET0_MDC__ENET0_MDC | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_MDIO__ENET0_MDIO | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET_CLK__CLKCTRL_ENET | MUX_CONFIG_ENET,
+
+	MX28_PAD_ENET0_COL__ENET1_TX_EN | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_CRS__ENET1_RX_EN | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_RXD2__ENET1_RXD0 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_RXD3__ENET1_RXD1 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_TXD2__ENET1_TXD0 | MUX_CONFIG_ENET,
+	MX28_PAD_ENET0_TXD3__ENET1_TXD1 | MUX_CONFIG_ENET,
+
+	/* I2C */
+	MX28_PAD_I2C0_SCL__I2C0_SCL,
+	MX28_PAD_I2C0_SDA__I2C0_SDA,
+
+	/* EMI */
+	MX28_PAD_EMI_D00__EMI_DATA0 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D01__EMI_DATA1 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D02__EMI_DATA2 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D03__EMI_DATA3 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D04__EMI_DATA4 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D05__EMI_DATA5 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D06__EMI_DATA6 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D07__EMI_DATA7 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D08__EMI_DATA8 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D09__EMI_DATA9 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D10__EMI_DATA10 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D11__EMI_DATA11 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D12__EMI_DATA12 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D13__EMI_DATA13 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D14__EMI_DATA14 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_D15__EMI_DATA15 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_ODT0__EMI_ODT0 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_DQM0__EMI_DQM0 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_ODT1__EMI_ODT1 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_DQM1__EMI_DQM1 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_DDR_OPEN_FB__EMI_DDR_OPEN_FEEDBACK | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_CLK__EMI_CLK | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_DQS0__EMI_DQS0 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_DQS1__EMI_DQS1 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_DDR_OPEN__EMI_DDR_OPEN | MUX_CONFIG_EMI,
+
+	MX28_PAD_EMI_A00__EMI_ADDR0 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A01__EMI_ADDR1 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A02__EMI_ADDR2 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A03__EMI_ADDR3 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A04__EMI_ADDR4 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A05__EMI_ADDR5 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A06__EMI_ADDR6 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A07__EMI_ADDR7 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A08__EMI_ADDR8 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A09__EMI_ADDR9 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A10__EMI_ADDR10 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A11__EMI_ADDR11 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A12__EMI_ADDR12 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A13__EMI_ADDR13 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_A14__EMI_ADDR14 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_BA0__EMI_BA0 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_BA1__EMI_BA1 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_BA2__EMI_BA2 | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_CASN__EMI_CASN | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_RASN__EMI_RASN | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_WEN__EMI_WEN | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_CE0N__EMI_CE0N | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_CE1N__EMI_CE1N | MUX_CONFIG_EMI,
+	MX28_PAD_EMI_CKE__EMI_CKE | MUX_CONFIG_EMI,
+
+	/* SPI2 (for flash) */
+	MX28_PAD_SSP2_SCK__SSP2_SCK | MUX_CONFIG_SSP2,
+	MX28_PAD_SSP2_MOSI__SSP2_CMD | MUX_CONFIG_SSP2,
+	MX28_PAD_SSP2_MISO__SSP2_D0 | MUX_CONFIG_SSP2,
+	MX28_PAD_SSP2_SS0__SSP2_D3 |
+		(MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP),
+};
+
+void board_init_ll(void)
+{
+	mxs_iomux_setup_multiple_pads(iomux_setup, ARRAY_SIZE(iomux_setup));
+	mx28_power_init();
+	mx28_mem_init();
+	mx28_power_wait_pswitch();
+}
+
+/* Support aparatus */
+inline void board_init_f(unsigned long bootflag)
+{
+	for (;;)
+		;
+}
+
+inline void board_init_r(gd_t *id, ulong dest_addr)
+{
+	for (;;)
+		;
+}
+
+inline void lowlevel_init(void) {}
+
+inline void __coloured_LED_init(void) {}
+inline void __red_LED_on(void) {}
+void coloured_LED_init(void)
+	__attribute__((weak, alias("__coloured_LED_init")));
+void red_LED_on(void)
+	__attribute__((weak, alias("__red_LED_on")));
+void hang(void) __attribute__ ((noreturn));
+void hang(void)
+{
+	for (;;)
+		;
+}
diff --git a/mmc_spl/board/denx/m28evk/power_init.c b/mmc_spl/board/denx/m28evk/power_init.c
new file mode 100644
index 0000000..419b452
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/power_init.c
@@ -0,0 +1,915 @@ 
+/*
+ * Freescale i.MX28 Boot PMIC init
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/regs-common.h>
+#include <asm/arch/regs-base.h>
+#include <asm/arch/regs-clkctrl.h>
+#include <asm/arch/regs-rtc.h>
+#include <asm/arch/regs-power.h>
+
+#include "m28_init.h"
+
+void mx28_power_clock2xtal(void)
+{
+	struct mx28_clkctrl_regs *clkctrl_regs =
+		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
+
+	/* Set XTAL as CPU reference clock */
+	writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+		&clkctrl_regs->hw_clkctrl_clkseq_set);
+}
+
+void mx28_power_clock2pll(void)
+{
+	struct mx28_clkctrl_regs *clkctrl_regs =
+		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
+
+	writel(CLKCTRL_PLL0CTRL0_POWER,
+		&clkctrl_regs->hw_clkctrl_pll0ctrl0_set);
+	early_delay(100);
+	writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+		&clkctrl_regs->hw_clkctrl_clkseq_clr);
+}
+
+void mx28_power_clear_auto_restart(void)
+{
+	struct mx28_rtc_regs *rtc_regs =
+		(struct mx28_rtc_regs *)MXS_RTC_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)
+		;
+
+	/*
+	 * Due to the hardware design bug of mx28 EVK-A
+	 * we need to set the AUTO_RESTART bit.
+	 */
+	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)
+		;
+}
+
+void mx28_power_set_linreg(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+void mx28_power_setup_5v_detect(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+void mx28_src_power_init(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+	early_delay(30);
+	clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER);
+}
+
+void mx28_power_init_4p2_params(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+void mx28_enable_4p2_dcdc_input(int xfer)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+		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);
+	}
+
+	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)
+		clrbits_le32(&power_regs->hw_power_ctrl,
+				POWER_CTRL_VBUS_VALID_IRQ);
+
+	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)
+		clrbits_le32(&power_regs->hw_power_ctrl,
+				POWER_CTRL_VDD5V_DROOP_IRQ);
+
+	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);
+}
+
+void mx28_power_init_4p2_regulator(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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 */
+	writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+		&power_regs->hw_power_5vctrl_clr);
+
+	/*
+	 * 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
+	 */
+	mx28_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);
+		writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+			&power_regs->hw_power_5vctrl_set);
+		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;
+				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);
+				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);
+}
+
+void mx28_power_init_dcdc_4p2_source(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+
+	if (!(readl(&power_regs->hw_power_dcdc4p2) &
+		POWER_DCDC4P2_ENABLE_DCDC)) {
+		hang();
+	}
+
+	mx28_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);
+		writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+			&power_regs->hw_power_5vctrl_set);
+	}
+}
+
+void mx28_power_enable_4p2(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+
+	mx28_power_init_4p2_params();
+	mx28_power_init_4p2_regulator();
+
+	/* Shutdown battery (none present) */
+	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);
+
+	mx28_power_init_dcdc_4p2_source();
+
+	writel(vdddctrl, &power_regs->hw_power_vdddctrl);
+	early_delay(20);
+	writel(vddactrl, &power_regs->hw_power_vddactrl);
+	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);
+}
+
+void mx28_boot_valid_5v(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+
+	mx28_power_enable_4p2();
+}
+
+void mx28_powerdown(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+void mx28_handle_5v_conflict(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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) {
+			mx28_powerdown();
+			break;
+		}
+
+		if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
+			mx28_boot_valid_5v();
+			break;
+		} else {
+			mx28_powerdown();
+			break;
+		}
+	}
+}
+
+int mx28_get_batt_volt(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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;
+}
+
+int mx28_is_batt_ready(void)
+{
+	return (mx28_get_batt_volt() >= 3600);
+}
+
+void mx28_5v_boot(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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) {
+		mx28_boot_valid_5v();
+		return;
+	}
+
+	early_delay(1000);
+	if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
+		mx28_boot_valid_5v();
+		return;
+	}
+
+	mx28_handle_5v_conflict();
+}
+
+void mx28_init_batt_bo(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+void mx28_switch_vddd_to_dcdc_source(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+int mx28_is_batt_good(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+	uint32_t volt;
+
+	volt = readl(&power_regs->hw_power_battmonitor);
+	volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
+	volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
+	volt *= 8;
+
+	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);
+	writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+		&power_regs->hw_power_5vctrl_clr);
+
+	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);
+	writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+		&power_regs->hw_power_5vctrl_clr);
+
+	early_delay(500000);
+
+	volt = readl(&power_regs->hw_power_battmonitor);
+	volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
+	volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
+	volt *= 8;
+
+	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;
+}
+
+void mx28_power_configure_power_source(void)
+{
+	mx28_src_power_init();
+
+	mx28_5v_boot();
+	mx28_power_clock2pll();
+
+	mx28_init_batt_bo();
+	mx28_switch_vddd_to_dcdc_source();
+}
+
+void mx28_enable_output_rail_protection(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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);
+}
+
+int mx28_get_vddio_power_source_off(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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_VDDDCTRL_LINREG_OFFSET_0STEPS) {
+				return 1;
+			}
+		}
+
+		if (!(readl(&power_regs->hw_power_5vctrl) &
+			POWER_5VCTRL_ENABLE_DCDC)) {
+			if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) ==
+				POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) {
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+
+}
+
+int mx28_get_vddd_power_source_off(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_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;
+}
+
+void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+	uint32_t cur_target, diff, bo_int = 0;
+	uint32_t powered_by_linreg = 0;
+
+	new_brownout = new_target - new_brownout;
+
+	cur_target = readl(&power_regs->hw_power_vddioctrl);
+	cur_target &= POWER_VDDIOCTRL_TRG_MASK;
+	cur_target *= 50;	/* 50 mV step*/
+	cur_target += 2800;	/* 2800 mV lowest */
+
+	powered_by_linreg = mx28_get_vddio_power_source_off();
+	if (new_target > cur_target) {
+
+		if (powered_by_linreg) {
+			bo_int = readl(&power_regs->hw_power_vddioctrl);
+			clrbits_le32(&power_regs->hw_power_vddioctrl,
+					POWER_CTRL_ENIRQ_VDDIO_BO);
+		}
+
+		setbits_le32(&power_regs->hw_power_vddioctrl,
+				POWER_VDDIOCTRL_BO_OFFSET_MASK);
+		do {
+			if (new_target - cur_target > 100)
+				diff = cur_target + 100;
+			else
+				diff = new_target;
+
+			diff -= 2800;
+			diff /= 50;
+
+			clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+				POWER_VDDIOCTRL_TRG_MASK, diff);
+
+			if (powered_by_linreg)
+				early_delay(1500);
+			else {
+				while (!(readl(&power_regs->hw_power_sts) &
+					POWER_STS_DC_OK))
+					;
+
+			}
+
+			cur_target = readl(&power_regs->hw_power_vddioctrl);
+			cur_target &= POWER_VDDIOCTRL_TRG_MASK;
+			cur_target *= 50;	/* 50 mV step*/
+			cur_target += 2800;	/* 2800 mV lowest */
+		} while (new_target > cur_target);
+
+		if (powered_by_linreg) {
+			writel(POWER_CTRL_VDDIO_BO_IRQ,
+				&power_regs->hw_power_ctrl_clr);
+			if (bo_int & POWER_CTRL_ENIRQ_VDDIO_BO)
+				setbits_le32(&power_regs->hw_power_vddioctrl,
+						POWER_CTRL_ENIRQ_VDDIO_BO);
+		}
+	} else {
+		do {
+			if (cur_target - new_target > 100)
+				diff = cur_target - 100;
+			else
+				diff = new_target;
+
+			diff -= 2800;
+			diff /= 50;
+
+			clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+				POWER_VDDIOCTRL_TRG_MASK, diff);
+
+			if (powered_by_linreg)
+				early_delay(1500);
+			else {
+				while (!(readl(&power_regs->hw_power_sts) &
+					POWER_STS_DC_OK))
+					;
+
+			}
+
+			cur_target = readl(&power_regs->hw_power_vddioctrl);
+			cur_target &= POWER_VDDIOCTRL_TRG_MASK;
+			cur_target *= 50;	/* 50 mV step*/
+			cur_target += 2800;	/* 2800 mV lowest */
+		} while (new_target < cur_target);
+	}
+
+	clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+			POWER_VDDDCTRL_BO_OFFSET_MASK,
+			new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
+}
+
+void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+	uint32_t cur_target, diff, bo_int = 0;
+	uint32_t powered_by_linreg = 0;
+
+	new_brownout = new_target - new_brownout;
+
+	cur_target = readl(&power_regs->hw_power_vdddctrl);
+	cur_target &= POWER_VDDDCTRL_TRG_MASK;
+	cur_target *= 25;	/* 25 mV step*/
+	cur_target += 800;	/* 800 mV lowest */
+
+	powered_by_linreg = mx28_get_vddd_power_source_off();
+	if (new_target > cur_target) {
+		if (powered_by_linreg) {
+			bo_int = readl(&power_regs->hw_power_vdddctrl);
+			clrbits_le32(&power_regs->hw_power_vdddctrl,
+					POWER_CTRL_ENIRQ_VDDD_BO);
+		}
+
+		setbits_le32(&power_regs->hw_power_vdddctrl,
+				POWER_VDDDCTRL_BO_OFFSET_MASK);
+
+		do {
+			if (new_target - cur_target > 100)
+				diff = cur_target + 100;
+			else
+				diff = new_target;
+
+			diff -= 800;
+			diff /= 25;
+
+			clrsetbits_le32(&power_regs->hw_power_vdddctrl,
+				POWER_VDDDCTRL_TRG_MASK, diff);
+
+			if (powered_by_linreg)
+				early_delay(1500);
+			else {
+				while (!(readl(&power_regs->hw_power_sts) &
+					POWER_STS_DC_OK))
+					;
+
+			}
+
+			cur_target = readl(&power_regs->hw_power_vdddctrl);
+			cur_target &= POWER_VDDDCTRL_TRG_MASK;
+			cur_target *= 25;	/* 25 mV step*/
+			cur_target += 800;	/* 800 mV lowest */
+		} while (new_target > cur_target);
+
+		if (powered_by_linreg) {
+			writel(POWER_CTRL_VDDD_BO_IRQ,
+				&power_regs->hw_power_ctrl_clr);
+			if (bo_int & POWER_CTRL_ENIRQ_VDDD_BO)
+				setbits_le32(&power_regs->hw_power_vdddctrl,
+						POWER_CTRL_ENIRQ_VDDD_BO);
+		}
+	} else {
+		do {
+			if (cur_target - new_target > 100)
+				diff = cur_target - 100;
+			else
+				diff = new_target;
+
+			diff -= 800;
+			diff /= 25;
+
+			clrsetbits_le32(&power_regs->hw_power_vdddctrl,
+					POWER_VDDDCTRL_TRG_MASK, diff);
+
+			if (powered_by_linreg)
+				early_delay(1500);
+			else {
+				while (!(readl(&power_regs->hw_power_sts) &
+					POWER_STS_DC_OK))
+					;
+
+			}
+
+			cur_target = readl(&power_regs->hw_power_vdddctrl);
+			cur_target &= POWER_VDDDCTRL_TRG_MASK;
+			cur_target *= 25;	/* 25 mV step*/
+			cur_target += 800;	/* 800 mV lowest */
+		} while (new_target < cur_target);
+	}
+
+	clrsetbits_le32(&power_regs->hw_power_vdddctrl,
+			POWER_VDDDCTRL_BO_OFFSET_MASK,
+			new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET);
+}
+
+void mx28_power_init(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+
+	mx28_power_clock2xtal();
+	mx28_power_clear_auto_restart();
+	mx28_power_set_linreg();
+	mx28_power_setup_5v_detect();
+	mx28_power_configure_power_source();
+	mx28_enable_output_rail_protection();
+
+	mx28_power_set_vddio(3300, 3150);
+
+	mx28_power_set_vddd(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);
+
+	early_delay(1000);
+}
+
+void mx28_power_wait_pswitch(void)
+{
+	struct mx28_power_regs *power_regs =
+		(struct mx28_power_regs *)MXS_POWER_BASE;
+
+	while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
+		;
+}
diff --git a/mmc_spl/board/denx/m28evk/start.S b/mmc_spl/board/denx/m28evk/start.S
new file mode 100644
index 0000000..48c2be6
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/start.S
@@ -0,0 +1,402 @@ 
+/*
+ *  armboot - Startup Code for ARM926EJS CPU-core
+ *
+ *  Copyright (c) 2003  Texas Instruments
+ *
+ *  ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
+ *
+ *  Copyright (c) 2001	Marius Groger <mag@sysgo.de>
+ *  Copyright (c) 2002	Alex Zupke <azu@sysgo.de>
+ *  Copyright (c) 2002	Gary Jennejohn <garyj@denx.de>
+ *  Copyright (c) 2003	Richard Woodruff <r-woodruff2@ti.com>
+ *  Copyright (c) 2003	Kshitij <kshitij@ti.com>
+ *  Copyright (c) 2010	Albert Aribaud <albert.u.boot@aribaud.net>
+ *
+ * Change to support call back into iMX28 bootrom
+ * Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+#if defined(CONFIG_OMAP1610)
+#include <./configs/omap1510.h>
+#elif defined(CONFIG_OMAP730)
+#include <./configs/omap730.h>
+#endif
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+.globl _start
+_start:
+	b	reset
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	b	reset
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+	.word	CONFIG_SYS_TEXT_BASE
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end__ - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * Store all registers on old stack pointer, this will allow us later to
+	 * return to the BootROM and let the BootROM load U-Boot into RAM.
+	 */
+	push	{r0-r12,r14}
+
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	bl	board_init_ll
+
+	pop	{r0-r12,r14}
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush v4 I/D caches
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
+
+	/*
+	 * disable MMU stuff and caches
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00002300	/* clear bits 13, 9:8 (--V- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/mmc_spl/board/denx/m28evk/u-boot.bd b/mmc_spl/board/denx/m28evk/u-boot.bd
new file mode 100644
index 0000000..3ddffbc
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/u-boot.bd
@@ -0,0 +1,14 @@ 
+sources {
+	u_boot_spl="mmc_spl/u-boot-spl.bin";
+	u_boot="u-boot.bin";
+}
+
+section (0) {
+        load u_boot_spl > 0x0000;
+        load ivt (entry = 0x0014) > 0x8000;
+	hab call 0x8000;
+
+        load u_boot > 0x40000100;
+        load ivt (entry = 0x40000100) > 0x8000;
+	hab call 0x8000;
+}
diff --git a/mmc_spl/board/denx/m28evk/u-boot.lds b/mmc_spl/board/denx/m28evk/u-boot.lds
new file mode 100644
index 0000000..f491bb5
--- /dev/null
+++ b/mmc_spl/board/denx/m28evk/u-boot.lds
@@ -0,0 +1,87 @@ 
+/*
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * January 2004 - Changed to support H4 device
+ * Copyright (c) 2004-2008 Texas Instruments
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+	. = 0x00000000;
+
+	. = ALIGN(4);
+	.text	:
+	{
+		start.o	(.text)
+		*(.text)
+	}
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+	. = ALIGN(4);
+	.data : {
+		*(.data)
+	}
+
+	. = ALIGN(4);
+	__u_boot_cmd_start = .;
+	.u_boot_cmd : { *(.u_boot_cmd) }
+	__u_boot_cmd_end = .;
+
+	. = ALIGN(4);
+
+	.rel.dyn : {
+		__rel_dyn_start = .;
+		*(.rel*)
+		__rel_dyn_end = .;
+	}
+
+	.dynsym : {
+		__dynsym_start = .;
+		*(.dynsym)
+	}
+
+	_end = .;
+
+	.bss __rel_dyn_start (OVERLAY) : {
+		__bss_start = .;
+		*(.bss)
+		 . = ALIGN(4);
+		__bss_end__ = .;
+	}
+
+	/DISCARD/ : { *(.bss*) }
+	/DISCARD/ : { *(.dynstr*) }
+	/DISCARD/ : { *(.dynsym*) }
+	/DISCARD/ : { *(.dynamic*) }
+	/DISCARD/ : { *(.hash*) }
+	/DISCARD/ : { *(.plt*) }
+	/DISCARD/ : { *(.interp*) }
+	/DISCARD/ : { *(.gnu*) }
+}