diff --git a/Makefile b/Makefile
index 64e0ea1..b5c1538 100644
--- a/Makefile
+++ b/Makefile
@@ -413,6 +413,7 @@ ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
 ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin
 ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin
 ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
+ALL-$(CONFIG_TPL) += $(obj)spl/u-boot-tpl.bin
 ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin
 ifneq ($(CONFIG_SPL_TARGET),)
 ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))
@@ -492,12 +493,25 @@ $(obj)u-boot.dis:	$(obj)u-boot
 		$(OBJDUMP) -d $< > $@
 
 
-
+ifdef CONFIG_TPL
+$(obj)u-boot-with-spl.bin: $(obj)spl/u-boot-spl.bin $(obj)spl/u-boot-tpl.bin \
+		$(obj)u-boot.bin
+		$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(CONFIG_SPL_PAD_TO) \
+			-I binary -O binary \
+			$(obj)spl/u-boot-spl.bin $(obj)spl/u-boot-spl-pad.bin
+		$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(CONFIG_SPL_PAD_TO) \
+			-I binary -O binary \
+			$(obj)spl/u-boot-tpl.bin $(obj)spl/u-boot-tpl-pad.bin
+		cat $(obj)spl/u-boot-spl-pad.bin $(obj)spl/u-boot-tpl-pad.bin \
+			$(obj)u-boot.bin > $@
+		rm $(obj)spl/u-boot-spl-pad.bin $(obj)spl/u-boot-tpl-pad.bin
+else
 $(obj)u-boot-with-spl.bin: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
 		$(OBJCOPY) ${OBJCFLAGS} --pad-to=$(CONFIG_SPL_PAD_TO) \
 			-I binary -O binary $< $(obj)spl/u-boot-spl-pad.bin
 		cat $(obj)spl/u-boot-spl-pad.bin $(obj)u-boot.bin > $@
 		rm $(obj)spl/u-boot-spl-pad.bin
+endif
 
 $(obj)u-boot-with-spl.imx: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
 		$(MAKE) -C $(SRCTREE)/arch/arm/imx-common \
@@ -621,7 +635,12 @@ $(obj)u-boot-nand.bin:	nand_spl $(obj)u-boot.bin
 		cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
 
 $(obj)spl/u-boot-spl.bin:	$(SUBDIR_TOOLS) depend
-		$(MAKE) -C spl all
+		$(MAKE) -C spl clean
+		$(MAKE) -C spl all CONFIG_SPL_BUILD=y
+
+$(obj)spl/u-boot-tpl.bin:	$(SUBDIR_TOOLS) depend
+		$(MAKE) -C spl clean
+		$(MAKE) -C spl all CONFIG_TPL_BUILD=y CONFIG_SPL_BUILD=y
 
 updater:
 		$(MAKE) -C tools/updater all
@@ -630,6 +649,7 @@ updater:
 # parallel sub-makes creating .depend files simultaneously.
 depend dep:	$(TIMESTAMP_FILE) $(VERSION_FILE) \
 		$(obj)include/spl-autoconf.mk \
+		$(obj)include/tpl-autoconf.mk \
 		$(obj)include/autoconf.mk \
 		$(obj)include/generated/generic-asm-offsets.h \
 		$(obj)include/generated/asm-offsets.h
@@ -704,8 +724,16 @@ $(obj)include/autoconf.mk: $(obj)include/config.h
 	$(CPP) $(CFLAGS) -DDO_DEPS_ONLY -dM include/common.h | \
 		sed -n -f tools/scripts/define2mk.sed > $@.tmp && \
 	mv $@.tmp $@
-
 # Auto-generate the spl-autoconf.mk file (which is included by all makefiles for SPL)
+$(obj)include/tpl-autoconf.mk: $(obj)include/config.h
+	@$(XECHO) Generating $@ ; \
+	set -e ; \
+	: Extract the config macros ; \
+	$(CPP) $(CFLAGS) -DCONFIG_TPL_BUILD  -DCONFIG_SPL_BUILD\
+			-DDO_DEPS_ONLY -dM include/common.h | \
+	sed -n -f tools/scripts/define2mk.sed > $@.tmp && \
+	mv $@.tmp $@
+
 $(obj)include/spl-autoconf.mk: $(obj)include/config.h
 	@$(XECHO) Generating $@ ; \
 	set -e ; \
@@ -716,12 +744,14 @@ $(obj)include/spl-autoconf.mk: $(obj)include/config.h
 
 $(obj)include/generated/generic-asm-offsets.h:	$(obj)include/autoconf.mk.dep \
 	$(obj)include/spl-autoconf.mk \
+	$(obj)include/tpl-autoconf.mk \
 	$(obj)lib/asm-offsets.s
 	@$(XECHO) Generating $@
 	tools/scripts/make-asm-offsets $(obj)lib/asm-offsets.s $@
 
 $(obj)lib/asm-offsets.s:	$(obj)include/autoconf.mk.dep \
 	$(obj)include/spl-autoconf.mk \
+	$(obj)include/tpl-autoconf.mk \
 	$(src)lib/asm-offsets.c
 	@mkdir -p $(obj)lib
 	$(CC) -DDO_DEPS_ONLY \
@@ -730,12 +760,14 @@ $(obj)lib/asm-offsets.s:	$(obj)include/autoconf.mk.dep \
 
 $(obj)include/generated/asm-offsets.h:	$(obj)include/autoconf.mk.dep \
 	$(obj)include/spl-autoconf.mk \
+	$(obj)include/tpl-autoconf.mk \
 	$(obj)$(CPUDIR)/$(SOC)/asm-offsets.s
 	@$(XECHO) Generating $@
 	tools/scripts/make-asm-offsets $(obj)$(CPUDIR)/$(SOC)/asm-offsets.s $@
 
 $(obj)$(CPUDIR)/$(SOC)/asm-offsets.s:	$(obj)include/autoconf.mk.dep \
-	$(obj)include/spl-autoconf.mk
+	$(obj)include/spl-autoconf.mk \
+	$(obj)include/tpl-autoconf.mk
 	@mkdir -p $(obj)$(CPUDIR)/$(SOC)
 	if [ -f $(src)$(CPUDIR)/$(SOC)/asm-offsets.c ];then \
 		$(CC) -DDO_DEPS_ONLY \
@@ -808,7 +840,8 @@ unconfig:
 	@rm -f $(obj)include/config.h $(obj)include/config.mk \
 		$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
 		$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \
-		$(obj)include/spl-autoconf.mk
+		$(obj)include/spl-autoconf.mk \
+		$(obj)include/tpl-autoconf.mk
 
 %_config::	unconfig
 	@$(MKCONFIG) -A $(@:_config=)
@@ -894,6 +927,7 @@ clobber:	tidy
 	@rm -f $(obj)nand_spl/{u-boot-nand_spl.lds,u-boot-spl,u-boot-spl.map}
 	@rm -f $(obj)spl/{u-boot-spl,u-boot-spl.bin,u-boot-spl.map}
 	@rm -f $(obj)spl/u-boot-spl.lds
+	@rm -f $(obj)spl/{u-boot-tpl,u-boot-tpl.bin,u-boot-tpl.map}
 	@rm -f $(obj)MLO MLO.byteswap
 	@rm -f $(obj)SPL
 	@rm -f $(obj)tools/xway-swap-bytes
diff --git a/README b/README
index a44d96a..7ab10e7 100644
--- a/README
+++ b/README
@@ -3092,6 +3092,10 @@ FIT uImage format:
 		option to re-enable it. This will affect the output of the
 		bootm command when booting a FIT image.
 
+- TPL framework
+		CONFIG_TPL
+		Enable building of TPL globally.
+
 Modem Support:
 --------------
 
@@ -4129,6 +4133,11 @@ Low Level (hardware related) configuration options:
 		that is executed before the actual U-Boot. E.g. when
 		compiling a NAND SPL.
 
+- CONFIG_TPL_BUILD
+		Modifies the behaviour of start.S  when compiling a loader
+		that is executed after the SPL and before the actual U-Boot.
+		It is loaded by the SPL.
+
 - CONFIG_SYS_MPC85XX_NO_RESETVEC
 		Only for 85xx systems. If this variable is specified, the section
 		.resetvec is not kept and the section .bootpg is placed in the
diff --git a/config.mk b/config.mk
index f42b655..6c0976d 100644
--- a/config.mk
+++ b/config.mk
@@ -161,6 +161,10 @@ CHECK	= sparse
 #########################################################################
 
 # Load generated board configuration
+ifeq ($(CONFIG_TPL_BUILD),y)
+# Include TPL autoconf
+sinclude $(OBJTREE)/include/tpl-autoconf.mk
+else
 ifeq ($(CONFIG_SPL_BUILD),y)
 # Include SPL autoconf
 sinclude $(OBJTREE)/include/spl-autoconf.mk
@@ -168,6 +172,7 @@ else
 # Include normal autoconf
 sinclude $(OBJTREE)/include/autoconf.mk
 endif
+endif
 sinclude $(OBJTREE)/include/config.mk
 
 # Some architecture config.mk files need to know what CPUDIR is set to,
@@ -239,6 +244,9 @@ endif
 
 ifeq ($(CONFIG_SPL_BUILD),y)
 CPPFLAGS += -DCONFIG_SPL_BUILD
+ifeq ($(CONFIG_TPL_BUILD),y)
+CPPFLAGS += -DCONFIG_TPL_BUILD
+endif
 endif
 
 # Does this architecture support generic board init?
@@ -310,10 +318,19 @@ ifneq ($(CONFIG_SYS_TEXT_BASE),)
 LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
 endif
 
+ifeq ($(CONFIG_TPL_BUILD),y)
+LDFLAGS_u-boot-tpl += -T $(obj)u-boot-spl.lds $(LDFLAGS_FINAL)
+ifneq ($(CONFIG_SPL_TEXT_BASE),)
+LDFLAGS_u-boot-tpl += -Ttext $(CONFIG_SPL_TEXT_BASE)
+endif
+else
+ifeq ($(CONFIG_SPL_BUILD),y)
 LDFLAGS_u-boot-spl += -T $(obj)u-boot-spl.lds $(LDFLAGS_FINAL)
 ifneq ($(CONFIG_SPL_TEXT_BASE),)
 LDFLAGS_u-boot-spl += -Ttext $(CONFIG_SPL_TEXT_BASE)
 endif
+endif
+endif
 
 # Linus' kernel sanity checking tool
 CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
diff --git a/doc/README.TPL b/doc/README.TPL
new file mode 100644
index 0000000..3056696
--- /dev/null
+++ b/doc/README.TPL
@@ -0,0 +1,71 @@
+Generic TPL framework
+=====================
+
+Overview
+--------
+
+TPL---Third Program Loader.
+
+Due to the SPL on some boards(powerpc mpc85xx) has a size limit and cannot
+be compatible with all the external device(e.g. DDR). So add a tertiary
+program loader (TPL) to enable a loader stub loaded by the code from the
+SPL. It loads the final uboot image into DDR, then jump to it to begin
+execution. Now, only the powerpc mpc85xx has this requirement and will
+implemente it.
+
+Keep consistent with SPL, with this framework almost all source files for a
+board can be reused. No code duplication or symlinking is necessary anymore.
+
+How it works
+------------
+
+There has been a directory TOPDIR/spl which contains only a Makefile. It is
+shared by SPL and TPL. By the way, TPL will share something with SPL, such
+as options defined in the board config files.
+
+The object files are built separately for SPL/TPL and placed in this
+directory. The final binaries which are generated are u-boot-{spl|tpl},
+u-boot-{spl|tpl}.bin and u-boot-{spl|tpl}.map.
+
+During the TPL build a variable named CONFIG_TPL_BUILD is exported in the
+make environment and also appended to CPPFLAGS with -DCONFIG_TPL_BUILD.
+Source files can be compiled for TPL with options choosed in the board
+config file, based on whether CONFIG_TPL_BUILD is set.
+
+For example:
+
+drivers/mtd/nand/Makefile:
+COBJS-$(CONFIG_SPL_NAND_INIT) += nand.o
+
+CONFIG_SPL_NAND_INIT is set in the include/configs/P1022DS.h:
+#ifdef CONFIG_TPL_BUILD
+#define CONFIG_SPL_NAND_INIT
+#endif
+
+The building of TPL images can be with:
+
+#define CONFIG_TPL
+
+Because TPL images normally have a different text base, one has to be
+configured by defining CONFIG_SPL_TEXT_BASE. The linker script has to be
+defined with CONFIG_SPL_LDSCRIPT. Likewise, these symbols are all shared
+with SPL, base on whether CONFIG_SPL_BUILD or CONFIG_TPL_BUILD is set.
+
+To support generic U-Boot libraries and drivers in the TPL binary one can
+optionally define CONFIG_SPL_XXX_SUPPORT. Currently following options
+are supported:
+
+CONFIG_SPL_SLIBCOMMON_SUPPORT (common/libcommon.o)
+CONFIG_SPL_LIBDISK_SUPPORT (disk/libdisk.o)
+CONFIG_SPL_I2C_SUPPORT (drivers/i2c/libi2c.o)
+CONFIG_SPL_GPIO_SUPPORT (drivers/gpio/libgpio.o)
+CONFIG_SPL_MMC_SUPPORT (drivers/mmc/libmmc.o)
+CONFIG_SPL_SERIAL_SUPPORT (drivers/serial/libserial.o)
+CONFIG_SPL_SPI_FLASH_SUPPORT (drivers/mtd/spi/libspi_flash.o)
+CONFIG_SPL_SPI_SUPPORT (drivers/spi/libspi.o)
+CONFIG_SPL_FAT_SUPPORT (fs/fat/libfat.o)
+CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o)
+CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o)
+CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/libnand.o)
+CONFIG_SPL_DMA_SUPPORT (drivers/dma/libdma.o)
+CONFIG_SPL_POST_MEM_SUPPORT (post/drivers/memory.o)
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bb81e84..e1f817a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -39,6 +39,7 @@ COBJS-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
 COBJS-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
 COBJS-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
 COBJS-$(CONFIG_SPL_NAND_BASE) += nand_base.o
+COBJS-$(CONFIG_SPL_NAND_INIT) += nand.o
 
 else # not spl
 
diff --git a/drivers/mtd/nand/fsl_elbc_spl.c b/drivers/mtd/nand/fsl_elbc_spl.c
index 50ff4fe..d00a13a 100644
--- a/drivers/mtd/nand/fsl_elbc_spl.c
+++ b/drivers/mtd/nand/fsl_elbc_spl.c
@@ -47,7 +47,10 @@ static void nand_wait(void)
 	}
 }
 
-static int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
+#ifndef CONFIG_TPL_BUILD
+static
+#endif
+int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
 {
 	fsl_lbc_t *regs = LBC_BASE_ADDR;
 	uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE;
diff --git a/include/nand.h b/include/nand.h
index 228d871..2aa7238 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -153,6 +153,9 @@ int nand_unlock(nand_info_t *meminfo, loff_t start, size_t length,
 int nand_get_lock_status(nand_info_t *meminfo, loff_t offset);
 
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst);
+#ifdef CONFIG_TPL_BUILD
+int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst);
+#endif
 void nand_deselect(void);
 
 #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
diff --git a/spl/Makefile b/spl/Makefile
index eef8c87..134a2f0 100644
--- a/spl/Makefile
+++ b/spl/Makefile
@@ -15,14 +15,27 @@
 # Based on top-level Makefile.
 #
 
-CONFIG_SPL_BUILD := y
+ifeq ($(CONFIG_SPL_BUILD),y)
 export CONFIG_SPL_BUILD
+endif
+ifeq ($(CONFIG_TPL_BUILD),y)
+export CONFIG_TPL_BUILD
+FILENAME := u-boot-tpl
+else
+FILENAME := u-boot-spl
+endif
 
 include $(TOPDIR)/config.mk
 
 # We want the final binaries in this directory
 obj := $(OBJTREE)/spl/
 
+clean:
+	@find $(obj) -type f \
+		\( -name 'core' -o -name '*.bak' -o -name '*~' \
+		-o -name '*.o'  -o -name '*.a' \) -print \
+		| xargs rm -f
+
 HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(SRCTREE)/board/$(VENDOR)/common/Makefile),y,n)
 
 ifdef	CONFIG_SPL_START_S_PATH
@@ -150,6 +163,7 @@ LDPPFLAGS += \
 	$(shell $(LD) --version | \
 	  sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')
 
+ifndef CONFIG_TPL_BUILD
 $(OBJTREE)/MLO:	$(obj)u-boot-spl.bin
 	$(OBJTREE)/tools/mkimage -T omapimage \
 		-a $(CONFIG_SPL_TEXT_BASE) -d $< $@
@@ -157,11 +171,12 @@ $(OBJTREE)/MLO:	$(obj)u-boot-spl.bin
 $(OBJTREE)/MLO.byteswap: $(obj)u-boot-spl.bin
 	$(OBJTREE)/tools/mkimage -T omapimage -n byteswap \
 		-a $(CONFIG_SPL_TEXT_BASE) -d $< $@
+endif
 
 $(OBJTREE)/SPL : $(obj)u-boot-spl.bin depend
 		$(MAKE) -C $(SRCTREE)/arch/arm/imx-common $@
 
-ALL-y	+= $(obj)u-boot-spl.bin
+ALL-y	+= $(obj)$(FILENAME).bin
 
 ifdef CONFIG_SAMSUNG
 ALL-y	+= $(obj)$(BOARD)-spl.bin
@@ -175,15 +190,15 @@ $(obj)$(BOARD)-spl.bin: $(obj)u-boot-spl.bin
 		$(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin
 endif
 
-$(obj)u-boot-spl.bin:	$(obj)u-boot-spl
+$(obj)$(FILENAME).bin:	$(obj)$(FILENAME)
 	$(OBJCOPY) $(OBJCFLAGS) -O binary $< $@
 
 GEN_UBOOT = \
 	cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(__START) \
 		--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-		-Map u-boot-spl.map -o u-boot-spl
+		-Map $(FILENAME).map -o $(FILENAME)
 
-$(obj)u-boot-spl:	depend $(START) $(LIBS) $(obj)u-boot-spl.lds
+$(obj)$(FILENAME):	depend $(START) $(LIBS) $(obj)u-boot-spl.lds
 	$(GEN_UBOOT)
 
 $(START):	depend
